I've got some bindings in UI:
<Window x:Class="Tester.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="377" Width="562" xmlns:my="clr-namespace:MyApp">
<Grid>
<TextBlock Text="{Binding Path=current.Text}" Name="Text1" />
<TextBlock Text="{Binding Path=current.o.Text}" Name="Text2" />
</Grid>
</Window>
Code:
class Coordinator : INotifyPropertyChanged{
List<Myclass1> list;
int currId = 0;
public Myclass1 current{
return list[currId];
}
public int CurrId
{
get { return currId; }
set
{
currId = value;
this.PropertyChanged(this,new PropertyChangedEventArgs("current"));
}
}
class Myclass1{
public string Text{get;}
public Myclass2 o{get;}
}
class Myclass2{
public string Text{get;}
}
When currId changes Tex1 in UI changes too,but Text2 doesn't.
I'm assuming this happens because Text2's source isn't updated.
Does anyone know how to fix it?
I'm not sure if this is what you are looking for, but for something similar I used the PropertyObserver class from Josh Smith's MVVM framework.
It should work assuming you implement your classes properly. With some fixes my code looks like this:
<Window x:Class="WpfBindingTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<StackPanel>
<TextBlock Text="Enter 0, 1 or 2 below and press Tab:"/>
<TextBox Text="{Binding CurrId}"/>
<Button/> <!--Button here is just for another tab stop-->
<TextBlock Text="{Binding Path=current.Text}" Name="Text1" />
<TextBlock Text="{Binding Path=current.o.Text}" Name="Text2" />
</StackPanel>
</Grid>
</Window>
it works fine with classes implemented like this:
public partial class Window1: Window {
public Window1() {
InitializeComponent();
DataContext = new Coordinator();
}
}
class Coordinator: INotifyPropertyChanged {
List<Myclass1> list;
int currId = 0;
public Myclass1 current {
get { return list[currId]; }
}
public int CurrId {
get { return currId; }
set {
currId = value;
this.PropertyChanged(this, new PropertyChangedEventArgs("current"));
}
}
public Coordinator() {
list = new List<Myclass1>(){
new Myclass1(){ Text = "1", o = new Myclass2(){Text="1.1"}},
new Myclass1(){ Text = "2", o = new Myclass2(){Text="2.2"}},
new Myclass1(){ Text = "3", o = new Myclass2(){Text="3.3"}}
};
}
public event PropertyChangedEventHandler PropertyChanged;
}
class Myclass1 {
public string Text { get; set; }
public Myclass2 o { get; set; }
}
class Myclass2 {
public string Text { get; set; }
}
Maybe you need to implement INotifyPropertyChanged in Myclass2 also.
Related
Im trying to create a function in a wpf program, where I can select an item in a listview, and press a button and it changes the tabitem and allows me to then edit the item from the listview that was selected. Im having issues with getting the tabitem to change for me.
For the navigation of my app, I have a ViewModelBase, which my AppointmentsViewModel inherits from. Inside the AppointmentsViewVM there is a tabcontrol with 4 items, by clicking each one it loads the requested view/viewmodel for that function.
This is not the only way I've tried to get this to work, Im currently on day 4. I could get the TabIndex to change in the TabControl earlier, but the tab would still not change for me. So I abandoned that and tried the below route (still no luck).
ViewModelBase
namespace MBR2.ViewModels
{
public class ViewModelBase : INotifyPropertyChanged
{
public ICommand MainMenuViewDogs_Command { get; set; }
public ICommand MainMenuViewAppointments_Command { get; set; }
private object _SelectedViewModel;
public object SelectedViewModel
{
get { return _SelectedViewModel; }
set
{
_SelectedViewModel = value;
OnPropertyChanged("SelectedViewModel");
}
}
public ViewModelBase()
{
MainMenuViewDogs_Command = new BaseCommand(OpenDogs);
MainMenuViewAppointments_Command = new BaseCommand(OpenAppointments);
}
private void OpenDogs(object obj)
{
SelectedViewModel = new DogsViewModel();
}
private void OpenAppointments(object obj)
{
SelectedViewModel = new AppointmentsViewModel();
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private bool _SelectedIndexView;
public bool SelectedIndexView
{
get { return _SelectedIndexView; }
set
{
_SelectedIndexView = value;
OnPropertyChanged("SelectedIndexView");
}
}
private bool _SelectedIndexAdd;
public bool SelectedIndexAdd
{
get { return _SelectedIndexAdd; }
set
{
_SelectedIndexView = value;
OnPropertyChanged("SelectedIndexAdd");
}
}
private bool _SelectedIndexEdit;
public bool SelectedIndexEdit
{
get { return _SelectedIndexEdit; }
set
{
_SelectedIndexView = value;
OnPropertyChanged("SelectedIndexEdit");
}
}
private bool _SelectedIndexDelete;
public bool SelectedIndexDelete
{
get { return _SelectedIndexDelete; }
set
{
_SelectedIndexView = value;
OnPropertyChanged("SelectedIndexDelete");
}
}
}
}
AppointmentsViewModel
{
public class AppointmentsViewModel : ViewModelBase
{
private AppointmentsAddVM _AppointmentsAddVM;
public AppointmentsAddVM AppointmentsAddVM { get { return _AppointmentsAddVM; } }
private AppointmentsEditVM _AppointmentsEditVM;
public AppointmentsEditVM AppointmentsEditVM { get { return _AppointmentsEditVM; } }
private AppointmentsDeleteVM _AppointmentsDeleteVM;
public AppointmentsDeleteVM AppointmentsDeleteVM { get { return _AppointmentsDeleteVM; } }
private AppointmentsViewVM _AppointmentsViewVM;
public AppointmentsViewVM AppointmentsViewVM { get { return _AppointmentsViewVM; } }
public ObservableCollection<object> ViewModelList { get; set; }
public AppointmentsViewModel()
{
this.ViewModelList = new ObservableCollection<object>();
_AppointmentsAddVM = new AppointmentsAddVM();
_AppointmentsEditVM = new AppointmentsEditVM();
_AppointmentsDeleteVM = new AppointmentsDeleteVM();
_AppointmentsViewVM = new AppointmentsViewVM();
this.ViewModelList.Add(_AppointmentsAddVM);
this.ViewModelList.Add(_AppointmentsEditVM);
this.ViewModelList.Add(_AppointmentsDeleteVM);
this.ViewModelList.Add(_AppointmentsViewVM);
}
}
}
AppointmentsView.xaml
<UserControl
x:Class="MBR2.Views.AppointmentsView"
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"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:vms="clr-namespace:MBR2.ViewModels.Appointments"
xmlns:views="clr-namespace:MBR2.Views.Appointments"
xmlns:viewmodels="clr-namespace:MBR2.ViewModels"
d:DataContext="{d:DesignInstance Type=viewmodels:AppointmentsViewModel}"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<DataTemplate DataType="{x:Type vms:AppointmentsViewVM}">
<views:AppointmentsViewView />
</DataTemplate>
<DataTemplate DataType="{x:Type vms:AppointmentsAddVM}">
<views:AppointmentsAddView />
</DataTemplate>
<DataTemplate DataType="{x:Type vms:AppointmentsDeleteVM}">
<views:AppointmentsDeleteView />
</DataTemplate>
<DataTemplate DataType="{x:Type vms:AppointmentsEditVM}">
<views:AppointmentsEditView />
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="Appointments" Width="Auto" Height="Auto">
<DockPanel HorizontalAlignment="Center"
Height="Auto"
LastChildFill="False"
VerticalAlignment="Top"
Width="Auto">
<TabControl x:Name="VMTabControl">
<TabItem x:Name="ViewTab"
TabIndex="0"
Header="View"
IsSelected="{Binding SelectedIndexView}"
Content="{Binding AppointmentsViewVM}"></TabItem>
<TabItem x:Name="AddTab"
TabIndex="1"
Header="Add"
IsSelected="{Binding SelectedIndexAdd}"
Content="{Binding AppointmentsAddVM}"></TabItem>
<TabItem x:Name="EditTab"
TabIndex="2"
Header="Edit"
IsSelected="{Binding SelectedIndexEdit}"
Content="{Binding AppointmentsEditVM}"></TabItem>
<TabItem x:Name="DeleteTab"
TabIndex="3"
Header="Delete"
IsSelected="{Binding SelectedIndexDelete}"
Content="{Binding AppointmentsDeleteVM}"></TabItem>
</TabControl>
</DockPanel>
</Grid>
</UserControl>
And the associated AppointmentsViewVM
namespace MBR2.ViewModels.Appointments
{
public class AppointmentsViewVM : ViewModelBase, INotifyPropertyChanged
{
private List<AppointmentsView_Wrapper> _AppointmentsView;
public List<AppointmentsView_Wrapper> AppointmentsView
{
get { return _AppointmentsView; }
set
{
_AppointmentsView = value;
OnPropertyChanged("AppointmentsView");
}
}
private List<string> _NameColumn = new List<string>();
public List<string> NameColumn
{
get { return _NameColumn; }
set
{
_NameColumn = value;
OnPropertyChanged("NameColumn");
}
}
private List<string> _ApptDateColumn = new List<string>();
public List<string> ApptDateColumn
{
get { return _ApptDateColumn; }
set
{
_ApptDateColumn = value;
OnPropertyChanged("ApptDateColumn");
}
}
private List<string> _ApptTimeColumn = new List<string>();
public List<string> ApptTimeColumn
{
get { return _ApptTimeColumn; }
set
{
_ApptTimeColumn = value;
OnPropertyChanged("ApptTimeColumn");
}
}
private List<string> _ApptVetColumn = new List<string>();
public List<string> ApptVetColumn
{
get { return _ApptVetColumn; }
set
{
_ApptVetColumn = value;
OnPropertyChanged("ApptVetColumn");
}
}
private List<string> _ApptCreatedColumn = new List<string>();
public List<string> ApptCreatedColumn
{
get { return _ApptCreatedColumn; }
set
{
_ApptCreatedColumn = value;
OnPropertyChanged("ApptCreatedColumn");
}
}
private List<int> _ApptIDColumn = new List<int>();
public List<int> ApptIDColumn
{
get { return _ApptIDColumn; }
set
{
_ApptIDColumn = value;
OnPropertyChanged("ApptIDColumn");
}
}
private string _AppointmentEdit_Enabled = "False";
public string AppointmentEdit_Enabled
{
get { return _AppointmentEdit_Enabled; }
set
{
_AppointmentEdit_Enabled = value;
OnPropertyChanged("AppointmentEdit_Enabled");
}
}
private AppointmentsView_Wrapper _ApptIDSelected;
public AppointmentsView_Wrapper ApptIDSelected
{
get { return _ApptIDSelected; }
set
{
AppointmentEdit_Enabled = "True";
_ApptIDSelected = value;
OnPropertyChanged("ApptIDSelected");
}
}
public AppointmentData AppointmentData = new AppointmentData();
public Messaging Messaging = new Messaging();
public ICommand AppointmentsListView_Command => new DelegateCommand<object>(AppointmentsListView_Clicked);
public ICommand EditSelection_Command => new DelegateCommand<object>(EditSelection_Clicked);
public AppointmentsViewVM()
{
BuildPage();
}
public async void BuildPage()
{
AppointmentsView = await AppointmentData.Appointments_GetAll();
foreach(var item in AppointmentsView)
{
ApptIDColumn.Add(item.ApptID);
NameColumn.Add(item.DogName);
ApptDateColumn.Add(item.ApptDate);
ApptTimeColumn.Add(item.ApptTime);
ApptVetColumn.Add(item.ApptVet);
ApptCreatedColumn.Add(item.ApptCreated.ToString("dd/mm/yyyy"));
}
}
public void AppointmentsListView_Clicked(object obj)
{
Messaging.ShowAlert(ApptIDSelected.ApptID.ToString());
}
public void EditSelection_Clicked(object obj)
{
bool result = Messaging.AskQuestion(ApptIDSelected.ApptID.ToString());
if(result)
{
SelectedIndexView = false;
SelectedIndexAdd = false;
SelectedIndexEdit = true;
SelectedIndexDelete = false;
OnPropertyChanged("SelectedIndexView");
OnPropertyChanged("SelectedIndexAdd");
OnPropertyChanged("SelectedIndexEdit");
OnPropertyChanged("SelectedIndexDelete");
}
else
{
Messaging.ShowAlert("no");
}
}
}
}
Here's a minimal reproduction of something where you select in a listbox and that then selects a corresponding tab in a tabcontrol.
This is very minimal but we can perhaps imagine a more sophisticated viewmodel per item in the listbox with name and viewmodel or something.
This is mainwindow.
<Window.Resources>
<DataTemplate DataType="{x:Type local:Avm}">
<local:Aview/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Bvm}">
<local:Bview/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Cvm}">
<local:Cview/>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<local:MainWindowViewmodel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListBox ItemsSource="{Binding ViewModels}"
x:Name="lb"
>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ViewModelName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TabControl Grid.Column="1"
ItemsSource="{Binding ViewModels}"
SelectedItem="{Binding ElementName=lb, Path=SelectedItem, Mode=TwoWay}"
>
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding ViewModelName}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
I have only done 3 views and viewmodels.
Note that the selecteditem of the listbox is bound twoway to the tabcontrol.
I have matching views and viewmodels A, B and C
MainWindowViewModel
public class MainWindowViewmodel : ViewModelBase
{
public ObservableCollection<Object> ViewModels { get; set; } = new ObservableCollection<Object>{
new Avm{ViewModelName="A viewmodel" },
new Bvm{ViewModelName="B viewmodel" },
new Cvm{ViewModelName="C viewmodel" }
};
}
Both the itemssource of listbox and tabcontrol are bound to that collection of viewmodels. Which are, as I mentioned, as simple as you get really.
Viewmodelbase
public class ViewModelBase : INotifyPropertyChanged
{
public string ViewModelName { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Avm, Bvm and Cvm just inherit from that.
An example usercontrol view.
<Grid>
<TextBlock Text="{Binding ViewModelName}"/>
</Grid>
</UserControl>
When I spin that up, select and select an item in the listbox the matching tab is selected. And vice versa. Select a tab and it selects the same one in the listbox.
I have a UserControl called "UserControllerIo" and this is what it has:
public ObservableCollection<string> Messages { get; set; }
public UserControllerIo()
{
Messages = new ObservableCollection<string>();
InitializeComponent();
IoComponentViewModel.Instance = new IoComponentViewModel();
Label1.DataContext = IoComponentViewModel.Instance;
Messages.Add(Label1.Text);
}
I consume this in my xml like so:
<Grid>
<Label>
<TextBlock x:Name="Label1" TextWrapping="WrapWithOverflow"
Text="{Binding Path=XState, Mode=OneWay}">
</TextBlock>
</Label>
<ListView
x:Name="ListView"
ItemsSource="{Binding Messages}" />
</Grid>
I have a view model for this control:
class IoComponentViewModel : INotifyPropertyChanged
{
public static IoComponentViewModel Instance { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private string _xState;
public string XState
{
get { return _xState; }
set
{
_xState = value;
OnPropertyChanged($"XState");
}
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
And I invoke to populate the list on another class like so:
case x:
IoComponentViewModel.Instance.XState = msg;
break;
My problem is, it is not showing in my Listview although I can see it in my label. Can you please show me how. Thank you.
I don't know how much I understood your task from the provided code, but look at this implementation variant.
IoComponentViewModel:
public class IoComponentViewModel : INotifyPropertyChanged
{
public static IoComponentViewModel Instance { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private string _xState;
public string XState
{
get { return _xState; }
set
{
if (_xState == value)
return;
XStates.Add(_xState = value);
OnPropertyChanged($"XState");
}
}
public ObservableCollection<string> XStates { get; } = new ObservableCollection<string>();
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
<Grid x:Name="PART_Grid">
<Grid.DataContext>
<local:IoComponentViewModel/>
</Grid.DataContext>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<!--<Label>-->
<TextBlock x:Name="Label1" TextWrapping="WrapWithOverflow"
Text="{Binding XState, Mode=OneWay}">
</TextBlock>
<!--</Label>-->
<ListView Grid.Row="1"
x:Name="ListView"
ItemsSource="{Binding XStates}" />
</Grid>
Code Behind:
//public ObservableCollection<string> Messages { get; set; }
public UserControllerIo()
{
//Messages = new ObservableCollection<string>();
InitializeComponent();
// IoComponentViewModel.Instance = new IoComponentViewModel();
//Label1.DataContext = IoComponentViewModel.Instance;
IoComponentViewModel.Instance = (IoComponentViewModel)PART_Grid.DataContext;
//Messages.Add(Label1.Text);
}
I misread the question initially. There are two problems. Your list is not binding to the view model, so you need an element reference.
<UserControl x:Class="StackOverflow.UserControllerIo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:StackOverflow"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
x:Name="MyUserControl"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label>
<TextBlock Foreground="Black" x:Name="Label1" TextWrapping="WrapWithOverflow"
Text="{Binding Path=XState, Mode=OneWay}">
</TextBlock>
</Label>
<ListView Grid.Row="1"
x:Name="ListView"
ItemsSource="{Binding Messages, ElementName=MyUserControl}" >
</ListView>
</Grid>
Secondly, at the point where you add Label1.Text to your data binding is not ready. So you will need to wait for binding before you read the text, for example in load event like this:
public partial class UserControllerIo : UserControl
{
public ObservableCollection<string> Messages { get; set; }
public UserControllerIo()
{
Messages = new ObservableCollection<string>();
InitializeComponent();
IoComponentViewModel.Instance = new IoComponentViewModel();
Label1.DataContext = IoComponentViewModel.Instance;
IoComponentViewModel.Instance.XState = "Something";
Loaded += UserControllerIo_Loaded;
}
private void UserControllerIo_Loaded(object sender, RoutedEventArgs e)
{
Messages.Add(Label1.Text);
}
}
EDIT:
my first tests mislead me, by testing with an int property for adding values to the List on runtime.
ObservableCollection updates anyway!
The problem is how you declared the Messages Property. If you have a Property on a Control it needs to be a dependency Property to notify the UI.
replace
public ObservableCollection<string> Messages { get; set; }
with
public ObservableCollection<string> Messages
{
get { return (ObservableCollection<string>)GetValue(MessagesProperty); }
set { SetValue(MessagesProperty, value); }
}
public static readonly DependencyProperty MessagesProperty =
DependencyProperty.Register("Messages", typeof(ObservableCollection<string>), typeof(UserControllerIo), new PropertyMetadata(null));
and you should be fine.
OR
you could imlpement INotifyPropertyChanged on your UserControl class.
And don't forget to maintain #Clemens' comment about binding!!!
ItemsSource="{Binding Messages, RelativeSource={RelativeSource AncestorType=UserControl}}
I'm trying to build a DTO to store the software configuration, but I'm stuck because my view is not sending the data to my ViewModel and also to my DTO.
I need to transfer 2 textbox and 3 combobox to my DTO, but using this code the values are always empty.
My ViewModel:
public class ViewModelProcessamentoArquivo : ViewModelBase
{
private PesquisaConfiguracao pesquisaConfiguracao;
public PesquisaConfiguracao PesquisaConfiguracao
{
get { return pesquisaConfiguracao; }
set
{
pesquisaConfiguracao = value;
base.OnPropertyChanged("PesquisaConfiguracao");
}
}
}
My DTO/Model
public class PesquisaConfiguracao
{
public string ArquivoOrigem { get; set; }
public string ArquivoDestino { get; set; }
public string TipoPesquisa { get; set; }
public string PesquisaVeicular { get; set; }
public string PesquisaCrediticia { get; set; }
}
And my View is like this.
<TextBox Name="txtBuscarArquivoOrigem" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Height="30" Margin="10, 0" Text="{Binding PesquisaConfiguracao.ArquivoOrigem}" />
<TextBox x:Name="txtBuscarArquivoDestino" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="3" Height="30" Margin="10, 0" Text="{Binding PesquisaConfiguracao.ArquivoDestino}" IsEnabled="false" />
...
Do you guys know why it's happening? I've used something similar in my other project and worked just fine. Also if you have any other possibly way to fix this issue, please comment!
First UpdateSourceTrigger PropertyChanged, that way the target (view) will update your source object on every change:
<TextBox Name="txtBuscarArquivoOrigem" Height="30" Text="{Binding PesquisaConfiguracao.ArquivoOrigem, UpdateSourceTrigger=PropertyChanged}" />
Then implement in your source object the INotifyPropertyChange Interface on it's properties in order to update the view when the value has changed:
private string _arquivoOrigem;
public string ArquivoOrigem
{
get
{
return _arquivoOrigem;
}
set
{
_arquivoOrigem = value;
OnPropertyChanged("ArquivoOrigem");
}
}
Put a BreakPoint in the property setter and it will break there when you change the value in the view TextBox.
If it doesn't work for you probably forgot to set your DataContext to your ViewModel:
<Window x:Class="WpfApplication1.MainWindow"
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"
Title="MainWindow"
DataContext="{StaticResource MainViewModel}">
Or did not initialize your source object:
public MainViewModel()
{
pesquisaConfiguracao = new PesquisaConfiguracao
{
ArquivoDestino = "aaa",
ArquivoOrigem = "bbb",
PesquisaCrediticia = "ccc",
PesquisaVeicular = "dddd",
TipoPesquisa = "eee"
};
}
How do I get my custom item collection to show up in my list view using WPF data bindings?
I have a tried to make a ViewModel and a custom collection that the ViewModel manipulates, in an attempt to get this collection to show up in a listview. I have a view model and a custom collection and a custom item class:
public class TranslationViewModel
{
public TranslationViewModel() { this.translatedItems = new TransListboxCollection(); }
public TransListboxCollection translatedItems { get; private set; }
public void addTranslatedItem(TransListboxItem message)
{
translatedItems.Add(message);
}
}
public class TransListboxCollection : BindingList<TransListboxItem>
{
public TransListboxCollection()
{
//initialize
}
}
public class TransListboxItem : INotifyPropertyChanged
{
private String _rawString;
private String _tString;
public String rawString
{
get { return _rawString; }
set { _rawString = value; NotifyPropertyChanged("rawString"); }
}
public String tString
{
get { return _tString; }
set { _tString = value; NotifyPropertyChanged("tString"); }
}
public TransListboxItem(String value)
{
this.tString = value;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public override string ToString()
{
return this.tString;
}
}
I have a WPF element hosted in a windows form
public partial class wGlobal : UserControl
{
public TranslationViewModel tvm { get; set; }
public wGlobal()
{
InitializeComponent();
this.DataContext = tvm;
}
}
The XAML code for such
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MHF_Transcoder_3" x:Class="MHF_Transcoder_3.wGlobal"
mc:Ignorable="d"
d:DesignWidth="1000" d:DesignHeight="150">
<Grid Width="1000" Height="150">
<ListView x:Name="listView1" ItemsSource="{Binding tvm}" HorizontalAlignment="Left" Width="1000" Height="150" VerticalAlignment="Top" Background="Black" Foreground="White" RenderTransformOrigin="0.5,0.5">
<DataTemplate>
<TextBlock Text="{Binding tString}" ToolTipService.ToolTip="{Binding rawString}" />
</DataTemplate>
</ListView>
</Grid>
and I have that element hosted in a windows form control
public partial class frmGlobal : Form
{
wGlobal xamlForm;
TranslationViewModel tvm;
public frmGlobal()
{
InitializeComponent();
tvm = new TranslationViewModel();
xamlForm = (wGlobal)elementHost1.Child;
xamlForm.tvm = tvm;
}
delegate void addMessageCallback(TransListboxItem message);
public void addMessage(TransListboxItem message) {
tvm.addTranslatedItem(message);
}
}
When I get the program up and launch everything, all my list view says is "System.Windows.DataTemplate". I've never really worked with WPF or data bindings before. I'm open to any and all advice and suggestions. Please help me get this setup and properly working.
Wrap Datatemplate with ItemTemplate
<ListView x:Name="listView1" ItemsSource="{Binding translatedItems}" HorizontalAlignment="Left" Width="1000" Height="150" VerticalAlignment="Top" Background="Black" Foreground="White" RenderTransformOrigin="0.5,0.5">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding tString}" ToolTipService.ToolTip="{Binding rawString}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Also as the tvm is the datacontext, you must bind to the collection "translatedItems"
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm just starting out with WPF and MVVM framework. I have a Window with two DataGrids and I would like to load data in one based on the row selection of the other.
Has anyone got any advice or examples ,I've tried numerous ways but none seem to work out.
Thank you
Look I can help you a little bit, you maybe need to monitor the selected item (either with binding or an event trigger). When it changes to use the new item to fetch the needed info from your data and then re-populate the source collection for the second data grid.
Here is a sample code it can help you:
Xaml
<DataGrid SelectedValue="{Binding Path=SelectedValue}"
ItemSource="{Binding Path=Source1}"/>
<DataGrid ItemSource="{Binding Path=Source2}"/>
Code Behind
public ObservableCollection Source1 { get; private set; }
public ObservableCollection<data> Source2 { get; private set; }
public Data SelectedValue
{
get { return _selectedValue; }
set
{
if (_selectedValue == value) return;
_selectedValue = value;
PopulateSource2();
}
}
private void PopulateSource2()
{
Source2.Clear();
//Get your other data from DB here
Source2.Add(SelectedValue);//This is just to show that it works
}
I am posting a simple code. You can change it as per your needs
View
<Window x:Class="MultipleDataGrid.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DataGrid Grid.Column="0" ItemsSource="{Binding SourceOne}" SelectedItem="{Binding SelectedItem}" />
<DataGrid Grid.Column="1" ItemsSource="{Binding SourceTwo}" />
</Grid>
</Window>
View Code Behind
using System.Windows;
namespace MultipleDataGrid
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
}
View Model
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Data;
namespace MultipleDataGrid
{
class ViewModel : INotifyPropertyChanged
{
private readonly object _lockOne = new object();
private readonly object _lockTwo = new object();
private ObservableCollection<StringValue> _sourceOne;
public ObservableCollection<StringValue> SourceOne
{ get { return _sourceOne; } }
private Dictionary<string, List<StringValue>> _sourceTwoList;
private List<StringValue> _sourceTwo;
public List<StringValue> SourceTwo
{
get { return _sourceTwo; }
set { _sourceTwo = value; RaisePropertyChanged("SourceTwo"); }
}
private StringValue _selectedItem;
public StringValue SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
PopulateDataGridTwo(value.Value);
RaisePropertyChanged("SelectedItem");
}
}
private void PopulateDataGridTwo(string key)
{
if (_sourceTwoList.ContainsKey(key))
{
SourceTwo = _sourceTwoList[key];
}
}
public ViewModel()
{
_sourceOne = new ObservableCollection<StringValue>
{
new StringValue("Key1"),new StringValue("Key2"),new StringValue("Key3")
};
_sourceTwoList = new Dictionary<string, List<StringValue>>();
BindingOperations.EnableCollectionSynchronization(_sourceOne, _lockOne);
BindingOperations.EnableCollectionSynchronization(_sourceTwoList, _lockTwo);
_sourceTwoList.Add("Key1", new List<StringValue> { new StringValue("KVOneOne"),new StringValue("KVOneTwo") });
_sourceTwoList.Add("Key2", new List<StringValue> { new StringValue("KVTwoOne"),new StringValue("KVTwoTwo") });
_sourceTwoList.Add("Key3", new List<StringValue> { new StringValue("KVThreeOne"),new StringValue("KVThreeTwo") });
RaisePropertyChanged("SourceOne");
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propName)
{
var pc = PropertyChanged;
if (pc != null)
pc(this, new PropertyChangedEventArgs(propName));
}
}
public class StringValue
{
public StringValue(string s)
{
_value = s;
}
public string Value { get { return _value; } set { _value = value; } }
string _value;
}
}
I have used the code from here to display the string in the DataGrid.
I hope the solution helps.
Here's a crude but working example that I decided to type up in between Battlefield rounds...
XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication3"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:Vm />
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<DataGrid x:Name="Selector" ItemsSource="{Binding Source}" />
<DataGrid Grid.Column="1" ItemsSource="{Binding SelectedItem, ElementName=Selector}" />
</Grid>
</Window>
Code:
namespace WpfApplication3
{
public class Vm
{
public ObservableCollection<ObserverableGrouping> Source { get; set; }
public Vm()
{
Source = new ObservableCollection<ObserverableGrouping>() {
new ObserverableGrouping("Group1"){ new ObjectModel() { Name = "A", Description = "Group1 Object1" }, new ObjectModel() { Name = "B", Description = "Group1 Object2" } },
new ObserverableGrouping("Group2"){ new ObjectModel() { Name = "C", Description = "Group2 Object1" }, new ObjectModel() { Name = "D", Description = "Group2 Object2" } }
};
}
}
public class ObserverableGrouping : ObservableCollection<ObjectModel>
{
public string GroupDescription { get; set; }
public ObserverableGrouping(string Name)
{
this.GroupDescription = Name;
}
}
public class ObjectModel
{
public string Name {get;set;}
public string Description {get;set;}
}
}
Hope this helps.