I have the problem with binding ComboBox in ListView
In ComboBox I need to bind User object from ListDetails object. If I change ComboBox it work, if I open window, binding don't work.
ComboBoxItem is a full list of all existing user from db.
<GridViewColumn x:Name="colUser" Header="User.Name in ComboBox">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox Width="300" SelectionChanged="ComboBox_SelectionChanged"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MainWindow}}, Path=AlleUser}"
SelectedValue="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}, Path=DataContext.User}"
SelectedValuePath="Key" DisplayMemberPath="Value"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
full code you can see in https://github.com/fialo4ka/ListBinding/tree/master
In example I change db loading to some test data
So... After trying all this answers I still can't see the name of user in loading form, so I found the solution directly put Name to the ComboBox.
but I still can't understand why all previous solution is not working for me :(
private void ComboBox_Loaded(object sender, RoutedEventArgs e)
{
((ComboBox)sender).Text = ((ListDetails)((ComboBox)sender).DataContext).User.Name;
}
<DataTemplate>
<ComboBox Width="300" SelectionChanged="ComboBox_SelectionChanged" Loaded="ComboBox_Loaded"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MainWindow}}, Path=AlleUser}"
SelectedValue="{Binding User}"
SelectedValuePath="Key" DisplayMemberPath="Key.Value"/>
You should bind to the User property of the ListDetails object:
<ComboBox Width="300" ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MainWindow}}, Path=AlleUser}"
SelectedValue="{Binding User}"
SelectedValuePath="Key" DisplayMemberPath="Key.Name"/>
First, you should never mix data binding and setting values directly in code-behind.It makes debugging and understanding the code much more difficult for everybody, including yourself. Choose one. I highly recommend data binding. I refactored the code to use data binding only.
The below code works for me. Values are displayed in the ComboBox.
If this is still not working as expected, you have to clarify exactly what you are doing, what you are expecting and what is actually happening.
Also you usually don't set the ItemsControl.SelctedValue property. This property holds the result of the ItemsControl.SelectedValuePath, once an item is selected. In your case, when the selected value should be the User.Name value, you would need to set the path to SelectedValuePath="Key.Name" as the Key references the User item of the KeyValuePair and then Name the User.Name property. You would bind the SelectedValue to a property in your MainWindow class, to access it there or to another control, e.g. TextBlock.Text.
When reading new data from the database, you first clear the collections and then add the new items. Since you are using an ObservableCollection the views will update automatically. Don't set the views directly.
MainWindow.xaml
<Window>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView Name="lvBezirke"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type main:MainWindow}}, Path=ListDetails}"
Grid.ColumnSpan="2">
<ListView.View>
<GridView ColumnHeaderToolTip="zugeordnete User je Bezirk">
<GridViewColumn x:Name="colBezirk" Header="Some Data from model" DisplayMemberBinding="{Binding Bezirk}" />
<GridViewColumn x:Name="colUser" Header="User.Name in ComboBox">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox Width="300" SelectionChanged="ComboBox_SelectionChanged"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type main:MainWindow}}, Path=AlleUser}"
SelectedValuePath="Key" DisplayMemberPath="Value" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="User.Loginname" DisplayMemberBinding="{Binding User.Loginname}" />
<GridViewColumn Header="User.Name" DisplayMemberBinding="{Binding User.Name}" />
</GridView>
</ListView.View>
</ListView>
<Button Grid.Row="1" Content="click" Click="Button_Click" />
<Button Grid.Row="1" Grid.Column="1" Content="clear" Click="Button_Click_1" />
<ListView Name="lvBezirkeClick"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type main:MainWindow}}, Path=ListDetailsClick}"
Grid.Row="2" Grid.ColumnSpan="2" >
<ListView.View>
<GridView ColumnHeaderToolTip="zugeordnete User je Bezirk">
<GridViewColumn Header="Some Data from model" DisplayMemberBinding="{Binding Bezirk}" />
<GridViewColumn Header="User.Loginname onClick" DisplayMemberBinding="{Binding User.Loginname}" />
<GridViewColumn Header="User.Name onClick" DisplayMemberBinding="{Binding User.Name}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
MainWindow.xaml.cs
partial class MainWindow
{
public ObservableCollection<ListDetails> ListDetails { get; set; }
public ObservableCollection<ListDetails> ListDetailsClick { get; set; }
public ObservableCollection<KeyValuePair<User, string>> AlleUser { get; set; }
public MainWindow()
{
InitializeComponent(); // Always the first line in constructor!
this.ListDetailsClick = new ObservableCollection<ListDetails>();
// Initialize ObservableCollection directly
this.ListDetails = new ObservableCollection<ListDetails>()
{
new ListDetails("data 1", new User("1 user", "1")),
new ListDetails("data 2", new User("8 user", "8")),
new ListDetails("data 3", new User("5 user", "5")),
};
this.AlleUser = new ObservableCollection<KeyValuePair<User, string>>()
{
{ new KeyValuePair<User, string>(new User("1 user", "1"), "1") },
{ new KeyValuePair<User, string>(new User("2 user", "2"), "2") },
{ new KeyValuePair<User, string>(new User("4 user", "3"), "3") },
{ new KeyValuePair<User, string>(new User("4 user", "4"), "4") },
{ new KeyValuePair<User, string>(new User("5 user", "5"), "5") },
{ new KeyValuePair<User, string>(new User("6 user", "6"), "6") },
{ new KeyValuePair<User, string>(new User("7 user", "7"), "7") },
{ new KeyValuePair<User, string>(new User("8 user", "8"), "8") },
};
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
// Clear and copy
private void Button_Click(object sender, RoutedEventArgs e)
{
this.ListDetailsClick.Clear();
this.ListDetails.ToList().ForEach(this.ListDetailsClick.Add);
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
this.ListDetailsClick.Clear();
}
}
Related
I have a ListView with checkboxes like this:
<ListView
x:Name="usersListView"
Width="300"
ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"
SelectionChanged="childrenListView_SelectionChanged"
Background="{StaticResource BackgroundPrimaryBrush}"
Foreground="{StaticResource WhiteBrush}"
Grid.Row="6" Grid.ColumnSpan="2"
>
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Tag="{Binding Id}" IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListViewItem}}, Path=IsSelected}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding FullName}" Header="Name" Width="250"/>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
All checkboxes in ListView are from List 'AllUsers' from database.
Now I want to set specific checkboxes to IsChecked=True in code behind.
I have another List 'Children' which have only few of the 'AllUsers' elements.
What I want is to display ListView with selected checkboxed binded to Persons in 'Children'.
I tried to implement this by myself with INotifyPropertyChanged implemented class wrapper to Person but I couldn't get Binding properly with this.
I hope I did explain the problem properly.
Thank you in advance :)
Consider using a IMultiValueConverter.
In the example below, my Children object is a simple string with the name. I have two list, the AllChildrens list and the SelectedChildrens list.
Foreach element in the AllChildrens collection, the converter checks if the element is contained into SelectedChildrens collection.
XAML: (I've removed the events)
<ListView ItemsSource="{Binding AllChildrens}" Tag="{Binding SelectedChildrens}">
<ListView.Resources>
<local:IEnumerableContainsConverter x:Key="Contains" />
</ListView.Resources>
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Content="{Binding}">
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource Contains}">
<Binding Path="." />
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type ListView}}" Path="Tag" />
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding FullName}" Header="Name" Width="250"/>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
ViewModel:
public class Model
{
public Model()
{
AllChildrens = new List<string>()
{
"James",
"Annabelle",
"Kevin",
"William",
"Joseph",
};
SelectedChildrens = new List<string>()
{
"James",
"Annabelle",
"William",
};
}
public List<string> AllChildrens { get; set; }
public List<string> SelectedChildrens { get; set; }
}
Converter:
class IEnumerableContainsConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values != null &&
values.Length == 2 &&
values[0] is string current_children && // Replace with your children object type
values[1] is IEnumerable<string> selected) // Replace with your children object type
{
return selected.Contains(current_children);
}
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I have a WPF ListView with checkbox in MVVM pattern. I need to accomplish the following two tasks.
1) Sort by any column when I click on column header. If column is already in ascending order then it should reorder in descending and vice versa.
2) SelectedTaskItem is not communicating with ViewModel when i check or uncheck a checkbox.
TaskView.xaml
<UserControl x:Class="MyProject.TaskView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="569" Width="954"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
>
<UserControl.Resources>
<DataTemplate x:Key="FirstCellCheckBox">
<CheckBox
Command="{Binding IsSelected, Mode= TwoWay}"
IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource
FindAncestor, AncestorType={x:Type ListViewItem}}}"
CommandParameter="{Binding Path=SelectedTaskItem,
ElementName=dgTaskList, UpdateSourceTrigger=PropertyChanged}"
/>
</DataTemplate>
</UserControl.Resources>
<ListView Grid.Row="1"
Name="ListViewTask"
Margin="12,49,26,79"
ItemsSource="{Binding TaskList}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
>
<ListView.View >
<GridView x:Name="gvTaskList">
<GridViewColumn Header="Select"
CellTemplate="{StaticResource FirstCellCheckBox}"
Width="30"/>
<GridViewColumn Header="Internal File"
DisplayMemberBinding="{Binding TaskID}"
Width="100"/>
<GridViewColumn Header="TaskDescription"
DisplayMemberBinding="{Binding TaskDescription}"
Width="100" />
<GridViewColumn Header="Task Status"
DisplayMemberBinding="{Binding TaskStatus}"
Width="100" />
</GridView>
</ListView.View>
</ListView>
TaskViewModel.cs
namespace MyProject
{
public class TaskViewModel: ViewModelBase
{
ObservableCollection<TaskModel> _TaskList;
public TaskViewModel()
{
TaskDAO dal = new TaskDAO();
_TaskList= dal.GetUpFileList();
}
public ObservableCollection<TaskModel> TaskList
{
get { return _TaskList; }
set
{
if (_TaskList!= value)
{
this._TaskList= value;
this.OnPropertyChanged("TaskList");
}
}
}
private TaskModel _selectedTaskItem;
public TaskModel SelectedTaskItem
{
get { return _selectedTaskItem; }
set
{
if (value != null)
{
_selectedTaskItem= value;
OnPropertyChanged("SelectedTaskItem");
if (null != _selectedTaskItem)
{
ObservableCollection<TaskModel> oCol =
new ObservableCollection<TaskModel>();
foreach (TaskModel itm in TaskList)
{
if (itm.TaskID == _selectedTaskItem.TaskID)
{
itm.IsSelected = true;
}
oCol.Add(itm);
}
TaskList.Clear();
TaskList = oCol;
OnPropertyChanged("TaskList");
}
}
}
}
}
You are binding the CheckBox's IsChecked value to ListBoxItem.IsChecked, but I don't see anything that binds ListBoxItem.IsChecked to your ViewModel.
Try adding the following to your ListBox.Resources
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
For sorting, I'd recommend using a DataGrid instead of a ListView, since sorting is built into the DataGrid. If you don't want to do that, you'll probably have to make some custom ListViewHeaders which execute a SortCommand in your ViewModel
i have a listview template and one column is a button. I need selected item when i click in this button. How i can do this ??
To cature the selected ListView item inside a button pressed event you can leverage the MVVM pattern. In my ListView, in the XAML, I bind the ItemsSource and SelectedItem to a ViewModel class. I also bind my button Command in the template to RunCommand in the ViewModel.
The tricky part is getting the binding correct from the template to the active DataContext.
Once you do this you can capture the SelectedCustomer inside the RunCommand that
gets executed when the button gets pressed.
I've included some of the code to help get you started.
You can find implementations of ViewModelBase and DelegateCommand via Google.
Here is the XAML:
<Window x:Class="ListViewScrollPosition.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main Window" Height="400" Width="400">
<Grid>
<ListView ItemsSource="{Binding Path=Customers}"
SelectedItem="{Binding Path=SelectedCustomer}"
Width="Auto">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Margin="6,2,6,2">
<TextBlock Text="{Binding FirstName}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Last Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Margin="6,2,6,2">
<TextBlock Text="{Binding LastName}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Address">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Margin="6,2,6,2">
<Button Content="Address"
Command="{Binding
Path=DataContext.RunCommand,
RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type ItemsControl}}}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
Here is the ViewModel:
using System.Collections.ObjectModel;
using System.Windows.Input;
using ListViewScrollPosition.Commands;
using ListViewScrollPosition.Models;
namespace ListViewScrollPosition.ViewModels
{
public class MainViewModel : ViewModelBase
{
public ICommand RunCommand { get; private set; }
public MainViewModel()
{
RunCommand = new DelegateCommand<object>(OnRunCommand, CanRunCommand);
_customers = Customer.GetSampleCustomerList();
_selectedCustomer = _customers[0];
}
private ObservableCollection<Customer> _customers =
new ObservableCollection<Customer>();
public ObservableCollection<Customer> Customers
{
get
{
return _customers;
}
}
private Customer _selectedCustomer;
public Customer SelectedCustomer
{
get
{
return _selectedCustomer;
}
set
{
_selectedCustomer = value;
OnPropertyChanged("SelectedCustomer");
}
}
private void OnRunCommand(object obj)
{
// use the SelectedCustomer object here...
}
private bool CanRunCommand(object obj)
{
return true;
}
}
}
Here is where I link in the ViewModel to the View:
public partial class MainView : Window
{
public MainView()
{
InitializeComponent();
DataContext = new ViewModels.MainViewModel();
}
}
Example with a regular click event in the code behind:
<ListView Height="167.96" VerticalAlignment="Top" ItemsSource="{Binding FulfillmentSchedules}" SelectedItem="{Binding SelectedFulfillmentSchedule}">
<ListView.View>
<GridView>
<GridViewColumn Header="Request">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}-{1}-{2}">
<Binding Path="Template.ProjectNumber" />
<Binding Path="Template.JobNumber" />
<Binding Path="Template.RequestId" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Template" DisplayMemberBinding="{Binding Template.Name}"/>
<GridViewColumn Header="Start Date" DisplayMemberBinding="{Binding StartDate}"/>
<GridViewColumn Header="Records" DisplayMemberBinding="{Binding Parameters.Records}"/>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Name="BtnYourButton" Content="Your Button" Click="BtnYourButton_Click" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Code behind:
private void BtnYourButton_Click(object sender, RoutedEventArgs e)
{
var boundData= (YourBoundDataType)((Button)sender).DataContext;
//do what you need to do here, including calling other methods on your VM
}
Note: While I certainly appreciate MVVM, I've come to accept that there is a pretty steep slope of dimminishing returns once you cross into actions and messaging between the form and the VM, so I use it only in cases of complex relationships between VMs or large singular VMs. For CRUD style data-centric applications I prefer to handle actions and message relay with the code behind.
I'm still learning WPF, but I'm really confused about something that should be really simple. What I want to do is to center the contents of the 3rd and 4th columns. When I run this, the columns are left justified:
<ListView Margin="0" x:Name="listMonitoredUrls" AlternationCount="1"
ItemsSource="{Binding}" >
<ListView.View>
<GridView>
<GridViewColumn Header="Description" DisplayMemberBinding="{Binding FriendlyDesc}"/>
<GridViewColumn Header="Url" DisplayMemberBinding="{Binding Url}"/>
<GridViewColumn Header="Frequency">
<GridViewColumn.CellTemplate >
<DataTemplate>
<TextBlock Text="{Binding ScanFrequencyMinutes}"
HorizontalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Next Scan" >
<GridViewColumn.CellTemplate >
<DataTemplate>
<TextBlock Text="{Binding TimeNextScanStr}"
HorizontalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
I"m really starting to like WPF, but some simple things like this seem to be really hard.
Try using the TextAlignment property instead of HorizontalAlignment - should do it.
To my understanding HorizontalAlignment="Center" will center your textblock not the text in it.
This might be a long shot but i've had to do it for listboxes where the items are defined by templates. Try setting the HorizontalContentAlignment="Stretch" on your ListView. If I don't set that the items take only as much space as they need and are left justified.
I've created a solution which works under the common scenario of:
<GridViewColumn Header="Some Property" DisplayMemberBinding="{Binding SomeProperty}" />
where one only wants a simple DisplayMemberBinding with text without having to specify a CellTemplate
the new code uses an attached property and becomes:
<GridViewColumn Header="Some Property" DisplayMemberBinding="{Binding SomeProperty}"
ctrl:GridViewExtensions.IsContentCentered="True" />
attached property code:
public static class GridViewExtensions
{
#region IsContentCentered
[Category("Common")]
[AttachedPropertyBrowsableForType(typeof(GridViewColumn))]
public static bool GetIsContentCentered(GridViewColumn gridViewColumn)
{
return (bool)gridViewColumn.GetValue(IsContentCenteredProperty);
}
public static void SetIsContentCentered(GridViewColumn gridViewColumn, bool value)
{
gridViewColumn.SetValue(IsContentCenteredProperty, value);
}
public static readonly DependencyProperty IsContentCenteredProperty =
DependencyProperty.RegisterAttached(
"IsContentCentered",
typeof(bool), // type
typeof(GridViewExtensions), // containing type
new PropertyMetadata(default(bool), OnIsContentCenteredChanged)
);
private static void OnIsContentCenteredChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
OnIsContentCenteredChanged((GridViewColumn)d, (bool)e.NewValue);
}
private static void OnIsContentCenteredChanged(GridViewColumn gridViewColumn, bool isContentCentered)
{
if (isContentCentered == false) { return; }
// must wait a bit otherwise GridViewColumn.DisplayMemberBinding will not yet be initialized,
new DispatcherTimer(TimeSpan.FromMilliseconds(100), DispatcherPriority.Normal, OnColumnLoaded, gridViewColumn.Dispatcher)
{
Tag = gridViewColumn
}.Start();
}
static void OnColumnLoaded(object sender, EventArgs e)
{
var timer = (DispatcherTimer)sender;
timer.Stop();
var gridViewColumn = (GridViewColumn)timer.Tag;
if (gridViewColumn.DisplayMemberBinding == null)
{
throw new Exception("Only allowed with DisplayMemberBinding.");
}
var textBlockFactory = new FrameworkElementFactory(typeof(TextBlock));
textBlockFactory.SetBinding(TextBlock.TextProperty, gridViewColumn.DisplayMemberBinding);
textBlockFactory.SetValue(TextBlock.TextAlignmentProperty, TextAlignment.Center);
var cellTemplate = new DataTemplate { VisualTree = textBlockFactory };
gridViewColumn.DisplayMemberBinding = null; // must null, otherwise CellTemplate won't be recognized
gridViewColumn.CellTemplate = cellTemplate;
}
#endregion IsContentCentered
}
Here is my example to show a working xaml:
<Window x:Class="WPF_Tutorial.Rich_text_controls.BlockUIContainerCenteredColumnSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:self="clr-namespace:WPF_Tutorial.Rich_text_controls"
Title="BlockUIContainerCenteredColumnSample" Height="275" Width="300"
WindowStartupLocation="CenterScreen">
<Window.Resources>
<x:Array x:Key="UserArray" Type="{x:Type self:User}">
<self:User Name="John Doe" Age="42" />
<self:User Name="Jane May-Anne Josephine Renalds Doe" Age="36" />
</x:Array>
</Window.Resources>
<Grid>
<FlowDocumentScrollViewer>
<FlowDocument>
<Paragraph FontSize="36" Margin="0">Users</Paragraph>
<Paragraph FontStyle="Italic" TextAlignment="Left" FontSize="14" Foreground="Gray">Here's a list of our users, inside our FlowDocument, in a completely interactive ListView control!</Paragraph>
<BlockUIContainer>
<ListView BorderThickness="0" ItemsSource="{StaticResource UserArray}" HorizontalAlignment="Center">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<!-- This stretches out the TextBlock width to the column width -->
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="150" />
<GridViewColumn>
<GridViewColumnHeader Content="Age" Width="75" />
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Age}" TextAlignment="Center" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</BlockUIContainer>
<Paragraph FontStyle="Italic" TextAlignment="Left" FontSize="14" Foreground="Gray">More content can go here...</Paragraph>
</FlowDocument>
</FlowDocumentScrollViewer>
</Grid>
</Window>
Notice the <ListView.ItemContainerStyle> block. It has the <Setter ....
Without this, as per AndyG's text, nothing will work the way you want.
This has been very frustrating trying to work out.
By the way, here is the backing-code for this xaml:
namespace WPF_Tutorial.Rich_text_controls
{
using System.Windows;
public partial class BlockUIContainerCenteredColumnSample : Window
{
public BlockUIContainerCenteredColumnSample()
{
InitializeComponent();
}
}
public class User
{
public int Age { get; set; }
public string Name { get; set; }
}
}
What you should see when run
I'm trying to display information from my ObservableCollection<MyData> in a ListView. MyData has:
string Name
string Location
int Progress
Using DataBinding, I'm able to display the Name and Location for all the items in my ObservableCollection<MyData> in their own column. But how can I add a Progress column with a ProgressBar inside? Progress is a percentage.
<ListView ItemsSource="{Binding PersonList}">
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="GameName" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Width="140" Header="Progress">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ProgressBar Maximum="100" Value="{Binding Progress}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Your ListView in XAML:
<ListView x:Name="DataView">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding Path=Name}" />
<ProgressBar Height="20" Width="100" Value="{Binding Path=Progress}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code-behind:
internal class MyData
{
public string Name { get; set; }
public int Progress { get; set; }
}
...
var items = new ObservableCollection<MyData>();
items.Add(new MyData() { Name = "Some", Progress = 25 });
items.Add(new MyData() { Name = "Another", Progress = 91 });
DataView.ItemsSource = items;
Just bind Progress property in MyData to the ProgressBar.Value and set the expected MAX value as the ProgressBar.Maximum for example 50 below
<ProgressBar Maximum="50" Value="{Binding Progress}" ..