Center a WPF ListView Column in "code behind" - c#

I am trying to center a column in a ListView in the code-behind. Since the columns are dynamically created during runtime, there is no option to do this in the XAML.
Here the helper I created. Setting the other properties like font color works fine - any ideas?
private void ListViewHelper(GridView gridView, ListView listView, MatrixId assignment, string key, IValueConverter converter)
{
// new column
GridViewColumn gridViewColumn = new GridViewColumn();
// header text and formating
gridViewColumn.Header = new TextBlock { Text = assignment.Id.ToString(), TextAlignment = TextAlignment.Center, Padding = new Thickness(7, 0, 0, 0), Width = 50 };
// databinding & converter
FrameworkElementFactory frameworkElementFactory = new FrameworkElementFactory(typeof(TextBlock));
DataTemplate dataTemplate = new DataTemplate();
dataTemplate.VisualTree = frameworkElementFactory;
gridViewColumn.CellTemplate = dataTemplate;
Binding binding = new Binding(assignment.Id.ToString() + key);
binding.Converter = converter;
// *** this does not work ***
frameworkElementFactory.SetValue(TextBlock.TextAlignmentProperty, TextAlignment.Right);
frameworkElementFactory.SetValue(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Right);
frameworkElementFactory.SetValue(TextBlock.ForegroundProperty, new SolidColorBrush(Color.FromRgb(100, 100, 100)));
frameworkElementFactory.SetBinding(TextBlock.TextProperty, binding);
// add column
gridView.Columns.Add(gridViewColumn);
}

If you want to center the content in a GridView inside a ListView, you can do it by creating an item container style for ListViewItem and set the HorizontalContentAlignment to Center.
var itemContainerStyle = new Style(typeof(ListViewItem));
var horizontalContentAlignmentSetter = new Setter(HorizontalContentAlignmentProperty, HorizontalAlignment.Center);
itemContainerStyle.Setters.Add(horizontalContentAlignmentSetter);
listView.ItemContainerStyle = itemContainerStyle;
Here, listView is your list view instance. The alignment will apply to all columns. If you need to align columns individually, set the HorizontalContentAlignment in the item container template to Stretch.
var itemContainerStyle = new Style(typeof(ListViewItem));
var horizontalContentAlignmentSetter = new Setter(HorizontalContentAlignmentProperty, HorizontalAlignment.Stretch);
itemContainerStyle.Setters.Add(horizontalContentAlignmentSetter);
listView.ItemContainerStyle = itemContainerStyle;
Then set the HorizontalAlignment of the controls inside the CellTemplate to what you need.
private void ListViewHelper(GridView gridView, ListView listView, MatrixId assignment, string key, IValueConverter converter)
{
// ...your code.
// Set the alignment to "Left", "Center", "Right" or "Stretch"
frameworkElementFactory.SetValue(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Right);
// ...your code.
}

Related

CheckBox rendered as a Label

I have a dynamically generated ListView, that uses data binding to allow editing some Boolean values through CheckBox. I use a IValueConverter to generate the ListView's columns (like in this answer):
public object Convert (object Value, Type EntryType, object Parameter, System.Globalization.CultureInfo Culture)
{
var Config = Value as ColumnConfig;
if (Config != null)
{
var GridView = new GridView ();
Binding NameBinding = new Binding ("Name");
GridViewColumn BaseColumn = new GridViewColumn { Header = "Settings",
DisplayMemberBinding = NameBinding,
Width = 125,
CellTemplate = new DataTemplate ()};
GridView.Columns.Add (BaseColumn);
foreach (Column CurrentColumn in Config.Columns)
{
Binding NewBinding = new Binding (CurrentColumn.DataField);
FrameworkElementFactory FEF = new FrameworkElementFactory (typeof (CheckBox));
FEF.SetBinding (CheckBox.IsCheckedProperty, NewBinding);
GridViewColumn GVColumn = new GridViewColumn
{
Header = CurrentColumn.Header,
DisplayMemberBinding = NewBinding
};
var DTemplate = new DataTemplate ();
DTemplate.VisualTree = FEF;
GVColumn.CellTemplate = DTemplate;
GridView.Columns.Add (GVColumn);
}
return GridView;
}
return Binding.DoNothing;
}
Which is used like so in the XAML:
<ListView Margin="2" ItemContainerStyle="{StaticResource LineHighlightListView}"
ItemsSource="{Binding InMatrixList}"
View="{Binding InMatrixColumns, Converter={StaticResource ConvertItemsToDynamicGridView}}" />
The columns' headers are generated elsewhere. The code should take in a ColumnConfig items, and create GridViewColumn objects that have a ChechBox databound to some other value elsewhere. However, all I am getting is columns with text in place of the CheckBoxes. The text is correct, so the data binding is valid, but the FrameworkElementFactory object is not working as expected.
Why are the checkboxes rendered/converted to textboxes?
Rule: avoid that way to dynamically compose a template.
I had a similar problem and I have solved as follows:
//see: http://www.codeproject.com/Articles/444371/Creating-WPF-Data-Templates-in-Code-The-Right-Way
private static DataTemplate CreateTemplate(UniprogCellVM cell)
{
var tcell = cell.GetType();
var sb = new StringBuilder();
sb.AppendFormat("<DataTemplate DataType=\"{{x:Type local:{0}}}\">", tcell.Name);
sb.Append("<local:UniprogCellControl ");
sb.Append("Content=\"{Binding Path=.}\" ");
sb.Append("Header=\"{Binding Path=.}\" ");
sb.AppendFormat("Style=\"{{DynamicResource Root{0}BoxStyleKey}}\" ", cell.Interaction);
sb.Append(">");
sb.Append("</local:UniprogCellControl>");
sb.Append("</DataTemplate>");
var context = new ParserContext();
context.XamlTypeMapper = new XamlTypeMapper(new string[0]);
context.XamlTypeMapper.AddMappingProcessingInstruction("local", tcell.Namespace, tcell.Assembly.FullName);
context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
context.XmlnsDictionary.Add("local", "local");
var template = (DataTemplate)XamlReader.Parse(sb.ToString(), context);
return template;
}
Basically, you should compose a fully-valid XAML of your template, then parse it with the parser.
Since the text-composition is a trivial task, you may pass any parameter in the creation function (as in my example above).
Just a final note: this approach is useful, but requires a computational effort because the runtime parsing and compilation. Avoid a large number of items created in such way.

Is it possible to edit a cell with a CheckBox and TextBlock

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.

What approach should I take when implementing a horizontal GridView in Xamarin.Forms?

I need to implement the horizontal (magazine style) list. The apps that do this quite good (in my opinion) are Flipboard and Zite. I wondered if this is possible to implement into a Xamarin.Forms application with existing resources.
In Xamarin.Forms, you have an excellent View that is the ListView. This ListView has an ItemSource and an ItemTemplate property where you can bind your ViewModel to the ItemSource and you can bind your TextCell class to your ItemTemplate.
I'm searching for the exact same thing except that you can modify the ItemTemplate to a custom class I make myself. The reason I need this is that I need a more complex layout than TextCelland the ListView only scrolls vertically.
I like the MVVM pattern very much and I need something that exactly fits into this pattern. Now, I looked into some implementations:
https://github.com/XLabs/Xamarin-Forms-Labs
http://forums.xamarin.com/discussion/18627/gridview-with-itemssource
Option 1
In the Xamarin.Forms.Labs, there is a GridView, but this view doesn't expand to its parent in my implementation although I am setting the following:
var grid = GridView {
ItemWidth = 50,
ItemHeight = 50,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
};
My ItemSource is tied to my ViewModel (which I am 100% sure of it is providing items. I know that because if I swap this GridView for a ListView, there are items.):
grid.ItemSource = ViewModel.Items;
And my ItemTemplate:
var cell = new DataTemplate(typeof(TextCell));
cell.SetBinding(TextCell.TextProperty, "Title");
cell.SetBinding(TextCell.TextProperty, "Description");
gridView.ItemTemplate = cell;
Now, I know there are some problems with the GridView and that the implementation is only for iOS right now according to this.
Option 2
In the second post they mention a WrapLayout. Although it shows some items being added via its Children property, it doesn't show any implementation with MVVM. Besides that, the implementation is nowhere near finished.
I can take this project as a base and expand it to my needs. But I feel there has to be a lot of work done for this to work in my scenario.
Does anybody know any other resources that better fit my needs than these two? For which option should I go if there aren't any resources available (I know there must be something available since Zite and Flipboard already done it)?
I dont know flipboard or zite but you try could something like this.
var grid = new Grid()
{
VerticalOptions = LayoutOptions.FillAndExpand,
ColumnDefinitions = new ColumnDefinitionCollection()
{
new ColumnDefinition(){ Width = new GridLength(250, GridUnitType.Absolute) },
new ColumnDefinition(){ Width = new GridLength(250, GridUnitType.Absolute) },
new ColumnDefinition(){ Width = new GridLength(250, GridUnitType.Absolute) },
new ColumnDefinition(){ Width = new GridLength(250, GridUnitType.Absolute) },
new ColumnDefinition(){ Width = new GridLength(250, GridUnitType.Absolute) },
new ColumnDefinition(){ Width = new GridLength(250, GridUnitType.Absolute) }
},
RowDefinitions = new RowDefinitionCollection()
{
new RowDefinition(){ Height = new GridLength(1,GridUnitType.Star) },
new RowDefinition(){ Height = new GridLength(1,GridUnitType.Star) },
new RowDefinition(){ Height = new GridLength(1,GridUnitType.Star) }
}
};
var scrollview = new ScrollView() { Orientation = ScrollOrientation.Horizontal };
scrollview.Content = grid;

Button content not updating using Frameworkelementfactory

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();

How to localize listview items text?

I am adding Items into the listview at design time,
but item's Text is not getting added to corresponding .resx file.
Do i need to set any property in Listview?
I have set Localize property of the underlaying Form to 'true'
private void PopulateListView()
{
ListView1.Width = 300;
ListView1.Location = new System.Drawing.Point(10, 50);
// Declare and construct the ColumnHeader objects.
ColumnHeader header1, header2;
header1 = new ColumnHeader();
header2 = new ColumnHeader();
// Set the text, alignment and width for each column header.
header1.Text = "Column1"; //Helper.getlocalStringResource("Xinga.LocalStrings.ColumnHeader.ResourceValue");
header1.Width = 100;
header2.Text = "Column2"; //Helper.getlocalStringResource("Xinga.LocalStrings.ColumnHeader.ResourceValue");
header2.Width = 100;
// Add the headers to the ListView control.
ListView1.Columns.Add(header1);
ListView1.Columns.Add(header2);
ListView1.View = View.Details; //important to see the headers
}
The header.Text can then be localized...
Switch the Language in form Properties window. Then change the Text property of your ListViewItem.
Check Other section in your resx or open it in Xml Editor.

Categories

Resources