I have been trying to create a ContentTemplate using the lovely Frameworkelementfactory.
The code works except I can't set the content of the Button. I have tried many things but I always end up with a Button with Content= Button.
Here is the code which generates the contenttemplate. For your further info, I am using this in a Tabcontrol Header Itemtemplate...
Cheers.
ControlTemplate ct = new ControlTemplate(typeof(TabItem));
FrameworkElementFactory spouter = new FrameworkElementFactory(typeof (DockPanel));
FrameworkElementFactory text = new FrameworkElementFactory(typeof(TextBlock));
text.SetValue(TextBlock.TextProperty, Name);
spouter.AppendChild(text);
FrameworkElementFactory mButtonPrev = new FrameworkElementFactory(typeof(Button));
mButtonPrev.SetValue(System.Windows.Controls.Button.ContentProperty, "x");
mButtonPrev.AddHandler(System.Windows.Controls.Button.ClickEvent, new RoutedEventHandler(CloseTab));
spouter.AppendChild(mButtonPrev);
ct.VisualTree = spouter;
return ct;
ControlTemplate ct = new ControlTemplate(typeof(TabItem));
Shouldn't you be creating a DataTemplate here instead?
(Everything else looks fine to me, also FEF is deprecated, read the docs)
For those of use still using FEF, I was able to set the content of my button with the actual string. I see Name as where "button" is coming from in your example. In my example, Name pulls up the class name that I'm binding to my datagrid.
var buttonTemplate = new FrameworkElementFactory(typeof(Button));
var text = new FrameworkElementFactory(typeof(TextBlock));
text.SetValue(TextBlock.TextProperty, "Save");
buttonTemplate.AppendChild(text);
buttonTemplate.AddHandler(
System.Windows.Controls.Primitives.ButtonBase.ClickEvent,
new RoutedEventHandler((o, e) => MessageBox.Show("hi"))
);
AccountDatagrid.Columns.Add(new DataGridTemplateColumn()
{
Header = "Save",
CellTemplate = new DataTemplate() { VisualTree = buttonTemplate }
});
AccountDatagrid.ItemsSource = AccoutDescCodeTime.GetBaseAccounts();
Related
I have the following coding where I bind a CheckBox and TextBlock into one DataGridTemplateColumn.
Would it be possible for me to edit the cell with the checkbox and textbox when I click on the cell itself to edit the text inside of it? I still want to be able to set my CheckBox to true or false at the same time as editing the text within the textblock.
Here is my coding:
private void btnFeedbackSelectSupplier_Click(object sender, RoutedEventArgs e)
{
DataGridTemplateColumn columnFeedbackSupplier = new DataGridTemplateColumn();
columnFeedbackSupplier.Header = "Supplier";
columnFeedbackSupplier.CanUserReorder = true;
columnFeedbackSupplier.CanUserResize = true;
columnFeedbackSupplier.IsReadOnly = false;
//My stack panel where I will host the two elements
var stackPanel = new FrameworkElementFactory(typeof(StackPanel));
stackPanel.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
DataTemplate cellTemplate = new DataTemplate();
//Where I create my checkbox
FrameworkElementFactory factoryCheck = new FrameworkElementFactory(typeof(CheckBox));
Binding bindCheck = new Binding("TrueFalse");
bindCheck.Mode = BindingMode.TwoWay;
factoryCheck.SetValue(CheckBox.IsCheckedProperty, bindCheck);
stackPanel.AppendChild(factoryCheck);
//Where I create my textblock
FrameworkElementFactory factoryText = new FrameworkElementFactory(typeof(TextBlock));
Binding bindText = new Binding("Supplier");
bindText.Mode = BindingMode.TwoWay;
factoryText.SetValue(TextBlock.TextProperty, bindText);
stackPanel.AppendChild(factoryText);
cellTemplate.VisualTree = stackPanel;
columnFeedbackSupplier.CellTemplate = cellTemplate;
DataGridTextColumn columnFeedbackSupplierItem = new DataGridTextColumn();
columnFeedbackSupplier.Header = (cmbFeedbackSelectSupplier.SelectedItem as DisplayItems).Name;
dgFeedbackAddCost.SelectAll();
IList list = dgFeedbackAddCost.SelectedItems as IList;
IEnumerable<ViewQuoteItemList> items = list.Cast<ViewQuoteItemList>();
var collection = (from i in items
let a = new ViewQuoteItemList { Item = i.Item, Supplier = i.Cost, TrueFalse = false }
select a).ToList();
dgFeedbackSelectSupplier.Columns.Add(columnFeedbackSupplier);
dgFeedbackSelectSupplier.ItemsSource = collection;
}
My example of how it looks now and how I would like to edit that R12 value inside the cell, while still being able to set the checkbox to true or false.
As for my original question, YES you can edit the cell with a CheckBox inside, but instead of a TextBlock I used a TextBox and I changed my the following coding from my question:
var stackPanel = new FrameworkElementFactory(typeof(StackPanel));
stackPanel.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);//Delete this line
To
var dockPanel = new FrameworkElementFactory(typeof(DockPanel));
Because a StackPanel does not have support for certain elements (like a TextBox) to fill the remaining available space, where a DockPanel does have support for it.
And then I added this line to make my TextBox fill the remaining space availble
factoryText.SetValue(TextBox.HorizontalAlignmentProperty, HorizontalAlignment.Stretch);
Hope this will help someone else out there :)
Why do you want to use TextBlock instead of TextBox ? If you want to expand the full width of my column length, then just set HorizontalAlignment to Stretch like that:
FrameworkElementFactory factoryText = new FrameworkElementFactory(typeof(TextBox));
factoryText.Text = HorizontalAlignment.Stretch;
Update:
And put your TextBox into Grid or DockPanel; as Zach Johnson says that StackPanel is meant for "stacking" things even outside the visible region, so it won't allow you to fill remaining space in the stacking dimension.
I am working in Xamarin.Forms, to try and create a Pop Up window which contains a ListView.
I am trying to use this structure:
var PopUp = new StackLayout
{
BackgroundColor = Color.Black, // for Android and WP
Orientation = StackOrientation.Vertical,
Children =
{
PLZOrt_Label, // my Label on top
SearchBarPLZOrt, // my SearchBar to the ListView
LVPLZOrt, // The Listview (all Cities/Zip-Codes in the Datasource -> List)
}
};
Taken from this guide page 13.
However, when I add a list view ( as detailed here ),
new Func<object> (delegate {
ListView listView = new ListView {
// Source of data items.
ItemsSource = devices,
ItemTemplate = new DataTemplate(() =>
{
// Create views with bindings for displaying each property.
Label nameLabel = new Label();
nameLabel.SetBinding(
Label.TextProperty, "{Binding Name, Converter={StaticResource strConverter}}"
);
Label IDLabel = new Label();
IDLabel.SetBinding(
Label.TextProperty, "{Binding Path=ID, Converter={StaticResource guidConverter}}"
);
return new ViewCell
{
View = new StackLayout
{
})
});
The "ItemTemplate" line throws up a "Cannot Convert Lambda expression to type 'System.Type' because it is not a Delegate Type"
In some other issues like this, it seems the solutions was to add a new action(() => {}) structure, but as this is a Xamarin approved method, I am not sure why I would need to implement this?
Thanks!
EDIT: With the addition of the top func line, I now get an error raised on that line, Error CS1643: Not all code paths return a value in anonymous method of type 'System.Func<object>'
As you can see from the constructors of DataTemplate here, you need to either pass a Func<object> or a Type.
You need to return something inside your statement block in order for it to be converted to a Func<object>. Since you have no return statement, the lambda isn't converted and the compiler thinks you're trying to use the DataTemplate(Type) constructor with wrong parameters. I don't know why the C# compiler chooses this constructor - I would guess that it's the first one it finds.
The example on the documentation page for the ListView page which you linked works because it returns a new ViewCell:
// ...
ItemTemplate = new DataTemplate(() =>
{
// Create views with bindings for displaying each property.
Label nameLabel = new Label();
nameLabel.SetBinding(Label.TextProperty, "Name");
Label birthdayLabel = new Label();
birthdayLabel.SetBinding(Label.TextProperty,
new Binding("Birthday", BindingMode.OneWay,
null, null, "Born {0:d}"));
BoxView boxView = new BoxView();
boxView.SetBinding(BoxView.ColorProperty, "FavoriteColor");
// Return an assembled ViewCell. <<--------------------------------------
return new ViewCell
{
View = new StackLayout
{
Padding = new Thickness(0, 5),
Orientation = StackOrientation.Horizontal,
Children =
{
boxView,
new StackLayout
{
VerticalOptions = LayoutOptions.Center,
Spacing = 0,
Children =
{
nameLabel,
birthdayLabel
}
}
}
}
};
})
// ...
EDIT: This is what I meant by put the lambda inside a new Func<object>(...):
ListView listView = new ListView
{
// Source of data items.
ItemsSource = devices,
ItemTemplate = new DataTemplate(new Func<object>(() =>
{
// Create views with bindings for displaying each property.
Label nameLabel = new Label();
nameLabel.SetBinding(
Label.TextProperty, "{Binding Name, Converter={StaticResource strConverter}}"
);
Label IDLabel = new Label();
IDLabel.SetBinding(
Label.TextProperty, "{Binding Path=ID, Converter={StaticResource guidConverter}}"
);
return new ViewCell
{
View = new StackLayout
};
}));
}
I have a question - I was coding happily a quick little feature to an app, which was a simple comparison output window.
Basically, user clicks a button and I generate a window with a datagrid of two columns of data.
It's all great and a five minutes code living inside one method with no unnecessary reference to anything else. The only problem I encountered was when I wanted to add a TopMost checkbox to this window.
How do I bind the IsChecked property of the box to the TopMost property of the window?
var checkbox = new CheckBox();
checkbox.Name = "cb";
checkbox.Content = "Top most";
var grid = new DataGrid();
grid.ItemsSource = wcList;
grid.Margin = new Thickness(5);
var panel = new StackPanel();
panel.Children.Add(checkbox);
panel.Children.Add(grid);
var win = new Window();
//Binding b = new Binding("cb");
//b.Mode = BindingMode.TwoWay;
//b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
//win.SetBinding(Window.TopmostProperty, b);
win.Title = "WordCount comparison";
win.Content = panel;
win.SizeToContent = SizeToContent.WidthAndHeight;
win.Icon = this.Icon;
win.Show();
This was supposed to be a 5-minutes one-off method, which is why I don't want to go as far as adding any xaml or properties into the code.
Cheers
Bartek
The other way around as you tried (in the commented code):
checkbox.SetBinding(CheckBox.IsCheckedProperty, new Binding("Topmost") { Source = win });
just after you instantiated your win variable.
How to: Sort items of a DataGrid by Content, not by Name
I am sorting my items of the DataGrid by Name, but I want to sort them by using the Content property. See the last line:
listView_BusinessContacts.Items.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
Here is my code, that sets the items using C# (WPF):
public void SetListViewItems()
{
int i = 0;
string[] companies = File.ReadAllLines(#"C:\Users\Companies.txt", Encoding.UTF8);
string itemName = string.Empty;
foreach (string company in companies)
{
Image image = new Image();
image.Source = new BitmapImage(new Uri(#"Images\folder.png", UriKind.Relative));
image.Stretch = Stretch.None;
Label label = new Label();
label.Content = companies[i];
DockPanel.SetDock(image, Dock.Left);
DockPanel.SetDock(label, Dock.Right);
DockPanel dockPanel = new DockPanel();
dockPanel.Children.Add(image);
dockPanel.Children.Add(label);
ListViewItem listViewItem = new ListViewItem();
listViewItem.Content = dockPanel;
itemName = label.Content.ToString();
listViewItem.Name = itemName.Replace(" ", "");
listViewItem.Selected += delegate
{
companyContent = label.Content.ToString();
SetItemsToDataGrid();
};
listView_BusinessContacts.Items.Add(listViewItem);
i++;
}
listView_BusinessContacts.Items.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
}
My problem is, that sorting by Content is not working.
Example output by using Name: HelloMyNameIsCompany
Example output by using Content: Hello My Name Is Company // NOT WORKING!
As you know, the Name property does not allow blank fields, so I need to Replace them. But I do not want to replace them - I want to use the Content, but that does not sort correctly. Do you know, how to fix that?
Thanks in advance.
Edit: First one is the txt file, second one is the application and the CORRECT sorting (unfortunately by using Name and the Replace method).
Sorry for hiding text, but the information in that file contain business matters.
Good afternoon everyone,
We have a XamDataGrid on our WPF application (VS 2010) and I need to programmatically add a control template for one field (fields are always added from code on our app).
So instead of creating the template on the XAML I am creating it from code (I followed several posts that explain similar issues) like this:
Field f = new Field { Name = name, Label = label, Width = new FieldLength(20) };
Style cellStyle = new System.Windows.Style();
string templateStr = "<ControlTemplate TargetType=\"{x:Type igDP:CellValuePresenter}\">" +
"<Button Content=\"Flu\" />" +
"</ControlTemplate>";
ParserContext pc = new ParserContext();
pc.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
pc.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
pc.XmlnsDictionary.Add("igDP", "http://infragistics.com/DataPresenter");
ControlTemplate ct = (ControlTemplate)XamlReader.Parse(templateStr, pc);
cellStyle.Setters.Add(new Setter() { Property = CellValuePresenter.TemplateProperty, Value = ((object)new CellValuePresenter() { Template = ct }) });
f.Settings.CellValuePresenterStyle = cellStyle;
MainDataGrid.FieldLayouts[0].Fields.Add(f);
Somehow this is not working and none of my fields/columns is displayed. So this is not working, any help will be appreciated.
Ok! I found it!
The problem was the way I was adding the setter to the ControlTemplate, so instead of:
cellStyle.Setters.Add(new Setter() { Property = CellValuePresenter.TemplateProperty, Value = ((object)new CellValuePresenter() { Template = ct }) });
It should be something like this:
cellStyle.Setters.Add(new Setter(CellValuePresenter.TemplateProperty, ct));
And then it works!
I know it is not the best way to do it but that's how I was asked to do it.