get Dialog Properties of bound ViewModel - wpf

for my app, I've created a popup- <Window> that is bound to a ViewModel.
The view model of the popup:
public class GeneratorSelectionViewModel : BaseViewModel
{
private Window mWindow;
public ICommand SelectedCommand { get; set; }
public GeneratorListItem SelectedItem { get; set; }
public GeneratorSelectionViewModel(Window window)
{
mWindow = window;
SelectedCommand = new RelayCommand(GeneratorSelected);
}
private void GeneratorSelected(object parameter)
{
if (SelectedItem != null)
{
mWindow.DialogResult = true;
}
}
}
...that is bound to this popupwindow (here the codebehind):
public partial class GeneratorSelectionPopup : Window
{
public GeneratorSelectionPopup()
{
InitializeComponent();
this.DataContext = new GeneratorSelectionViewModel(this);
}
}
In that window, I have a listbox, where SelectedItem is bound to SelectedItem-property of the VM.
I call this Popup the following way:
GeneratorSelectionPopup SelectionPopup = new GeneratorSelectionPopup();
SelectionPopup.ShowDialog();
Now my question...
How can I transfer that public property SelectedItem from the popups viewmodel to the MainWindow?
`SelectionPopup.SelectedItems` isn't available.

Cast the DataContext of the window:
GeneratorSelectionPopup SelectionPopup = new GeneratorSelectionPopup();
SelectionPopup.ShowDialog();
var selectedItem = (SelectionPopup.DataContext as GeneratorSelectionViewModel).SelectedItem;

You could use an event handler
public partial class GeneratorSelectionPopup : Window
{
public event EventHandler<MyEventArgs> ButtonOkClicked;
public GeneratorSelectionViewModel ViewModel;
public GeneratorSelectionPopup()
{
InitializeComponent();
ViewModel = new GeneratorSelectionViewModel(this);
this.DataContext = ViewModel
}
private void HandleOkButtonClick(object sender, RoutedEventArgs e)
{
ButtonOkClicked?.Invoke(this, new MyEventArgs
{
SelectedItem = this.ViewModel.SelectedItem
});
Window.GetWindow(this).Close();
}
}
public class MyEventArgs: EventArgs
{
public GeneratorListItem SelectedItem { get; set; }
}
And in the mainwindow cs:
GeneratorSelectionPopup SelectionPopup = new GeneratorSelectionPopup();
SelectionPopup.ButtonOkClicked += OnButtonOkClicked;
SelectionPopup.ShowDialog();
private void OnButtonOkClicked(object sender, MyEventArgs e)
{
}

Related

WPF, why adding PropertyChanged to List<> does not take into effect?

why PropertyChangedEvent can be add to a String property, but cannot be add to a List<> property?
the xaml likes this:
<StackPanel>
<ListBox ItemsSource="{Binding Items}" Height="300"/>
<Button Click="Button_Click">Change</Button>
</StackPanel>
and the xaml.cs like this:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
//public ObservableCollection<String> Items { get; set; } = new ObservableCollection<String>(); // ok
public List<String> Items // no effect
{
get { return _items; }
set
{
_items = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Items"));
}
}
private List<String> _items = new List<string>();
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
Items.Add("aaa");
Items.Add("bbb");
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Items.Clear();
for (int i = 0; i < 5; i++)
Items.Add(i.ToString());
}
}
Your issue can be fixed in multiple ways,
Create another List on Button Click, sample code given below
Use Observable Collection
Change
private RelayCommand _buttonClick;
public RelayCommand ButtonClick => _buttonClick ?? new RelayCommand(onButtonClick, canButtonClick);
private bool canButtonClick(object obj)
{
return true;
}
private void onButtonClick(object obj)
{
List<String> tempItems = new List<string>();
for (int i = 0; i < 5; i++)
tempItems.Add(i.ToString());
Items = tempItems;
}
It doesn't work because you're only notifying when the entire List is set, not when items are added or removed within the list.
Use an ObservableCollection<string> instead of List<string>:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<string> _Items = new ObservableCollection<string>();
public ObservableCollection<string> Items
{
get { return _Items; }
set
{
_Items = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Items));
}
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
Items.Add("aaa");
Items.Add("bbb");
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Items.Clear();
for (int i = 0; i < 5; i++)
Items.Add(i.ToString());
}
}

How to add files into my binding ListView with Pure XAML

So i have Page with Button and ListView.
Via this Button the user select files that i want to add into my ListView
<Page.Resources>
<vm:ViewModelBase x:Key="ViewModelBase"/>
</Page.Resources>
<Button Command="{Binding AddFilesCommand, Source={StaticResource ViewModelBase}}"/>
<ListView ItemsSource="{Binding Files}"/>
My ViewModel:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<FileBase> _files;
public AddFilesCommand AddFilesCommand { get; set; }
public ViewModelBase()
{
_files = new ObservableCollection<FileBase>();
AddFilesCommand = new AddFilesCommand(this);
}
public void AddFile()
{
OpenFileDialog openFileDialog = new OpenFileDialog
{
Title = "Please Select File(s)",
Multiselect = true
};
if (openFileDialog.ShowDialog() == true)
{
string[] files = openFileDialog.FileNames;
if (files.Length > 0)
AddFile(files);
}
}
public void AddFile(string[] files)
{
// Here i am add all my files into my Files collection
}
public ObservableCollection<FileBase> Files
{
get { return _files; }
set
{
_files= value;
NotifyPropertyChanged();
}
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
AddFilesCommand
public class AddFilesCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public bool canExecute { get; set; }
public ViewModelBase ViewModel { get; set; }
public AddFilesCommand(ViewModelBase viewModel)
{
canExecute = true;
ViewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return canExecute;
}
public void Execute(object parameter)
{
ViewModel.AddFile();
}
}
Now this works fine and i can see the all the files that the user select are inside my Files collection but i cannot see this files inside my ListView

command not binding properly

Please find the code used for simple binding.
Xaml code:
Button Command="{Binding BoldCommand}"
C# code:
public partial class MainWindow : RibbonWindow
{
public BoldCommand BoldCommand
{
get;
set;
}
public MainWindow()
{
InitializeComponent();
BoldCommand = new BoldCommand();
DataContext = BoldCommand;
}
}
public class BoldCommand : ICommand
{
public BoldCommand()
{
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
}
}
The problem is that your BoldCommand in your DataContext does not have a BoldCommand property.
The major problem you are going to have is that you have conjoined your View and ViewModel. Replace your MainWindow code with the following and it should work.
public partial class MainWindow : RibbonWindow
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
public class MainViewModel
{
public MainViewModel()
{
BoldCommand = new BoldCommand();
}
public BoldCommand BoldCommand { get; set; }
}

Why is my Silverlight usercontrol property null?

I have a usercontrol:
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock Name="TextBlock1" Text="Text for"></TextBlock>
</Grid>
It has a cs file:
public partial class MyUserControl: UserControl
{
public string MyProperty { get; set; }
public MyUserControl()
{
InitializeComponent();
DoSomething();
}
private void DoSomething()
{
TextBlock1.Text = TextBlock1.Text + MyProperty;
}
}
I'm trying to add this usercontrol programatically to another user control:
UserControls.MyUserControl myUserControl = new UserControls.MyUserControl();
myUserControl.MyProperty = "Something";
MyStackPanel.Children.Add(myUserControl);
I thought I've done something like this before without any issues, but in this case MyProperty is always null. What did I do wrong?
Your code is fine as-is except for when you are calling DoSomething(). You should avoid GUI interaction in the constructor of a control for many reasons (not the least of which is that your property is not yet set as pointed out by Mark Hall). I do not however recommend adding different constructors just to take initial properties.
You simply want to defer that call to the Loaded event of the control.
Assuming you set the event in the Xaml like this:
<navigation:Page x:Class="MyUserControl"
...
Loaded="Page_Loaded">
Your code would look like:
public partial class MyUserControl: UserControl
{
public string MyProperty { get; set; }
public MyUserControl()
{
InitializeComponent();
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
DoSomething();
}
private void DoSomething()
{
TextBlock1.Text = TextBlock1.Text + MyProperty;
}
}
If you want to set the Loaded event in code it would just look like:
public partial class MyUserControl: UserControl
{
public string MyProperty { get; set; }
public MyUserControl()
{
InitializeComponent();
Loaded += Page_Loaded;
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
DoSomething();
}
private void DoSomething()
{
TextBlock1.Text = TextBlock1.Text + MyProperty;
}
}
The it is just down to you setting all your desired properties after construction, but before the page is loaded as you are doing already.
UserControls.MyUserControl myUserControl = new UserControls.MyUserControl();
myUserControl.MyProperty = "Something";
MyStackPanel.Children.Add(myUserControl); // This makes it visible when Loaded event is called
What is happening is that you are calling DoSomething in your contructor before you have set MyProperty so MyProperty is equal to null. If you want the data to be there when the UserControl is created you can set it in the Constructor.
i.e.
public partial class MyUserControl : UserControl
{
public string MyProperty { get; set; }
public MyUserControl() //Default Constructor
{
InitializeComponent();
}
public MyUserControl(string MyData)
{
InitializeComponent();
MyProperty = MyData;
DoSomething();
}
private void DoSomething()
{
TextBlock1.Text = TextBlock1.Text + MyProperty;
}
}
and create it like this.
MyUserControl myUserControl = new MyUserControl(" Something");
MyStackPanel.Children.Add(myUserControl);

WPF binding doesn't work

I have simplified example:
XAML:
<CheckBox IsChecked="{Binding Path=IsSelected, Mode=TwoWay}" Name="cb" />
<Button Name="button1" Click="button1_Click" />
Code behind:
public partial class MainWindow : Window
{
private ObservableCollection<MyObject> collection = new ObservableCollection<MyObject>();
public MainWindow()
{
InitializeComponent();
collection.Add(new MyObject(true));
//grid.DataContext = collection[0];
}
private void button1_Click(object sender, RoutedEventArgs e)
{
collection[0].IsSelected = false;
}
}
public class MyObject
{
public bool IsSelected { get; set; }
public MyObject(bool isSelected)
{
this.IsSelected = isSelected;
}
}
The cb.IsChecked doesn't change by button clicking though the collection[0].IsSelected is changed.
Even if I uncomment grid.DataContext = collection[0]; - nothing changed.
In real example I have the same checkbox in the item template of a listbox. So the behaviour is the same - the selection of checkboxes don't change.
You need to implement INotifyPropertyChanged on your MyObject type
Please try the following codes:
public class MyObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
NotifyPropertyChanged("IsSelected");
}
}
public MyObject(bool isSelected)
{
this.IsSelected = isSelected;
}
}

Resources