How to make changes to objects in the page above - c#

I have a NavigationView that loads a page into its associated frame.
On the loaded page there is a button, how can I use this button to change the properties of the NavigationView.
I know that to update the page in the frame is:
Frame.Navigate(typeof(Window2));
So I thought it might be:
Frame.NavigationView.IsEnabled = False
But this isn't valid.
Is there a way to do this?

You can not set NavigationView.IsEnabled directly from loaded page.You can set a property in a viewmodel to bind with the IsEnabled of navigationView.When you navigate a new page by Frame.Navigate(),pass the viewmodel to the new page.You can set the property to false when you click the button in the page.In this case,the navigationView will be disabled.
.xaml:
<NavigationView IsEnabled="{x:Bind MyViewModel.IsEnabled,Mode=OneWay}">
<NavigationView.MenuItems>
<NavigationViewItem Content="Item 1"></NavigationViewItem>
</NavigationView.MenuItems>
<Frame x:Name="ContentFrame"/>
</NavigationView>
.cs:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private bool isEnabled = false;
public bool IsEnabled {
get { return isEnabled; }
set {
isEnabled = value;
OnPropertyChanged();
}
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public sealed partial class MainPage: Page
{​
public MainPage()​
{​
this.InitializeComponent();​
MyViewModel = new ViewModel();
}
private ViewModel MyViewModel { get; set; }
}
When you want to navigate a new page,pass the viewmodel:
ContentFrame.Navigate(typeof(Page1),MyViewModel);
Page1.cs:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
isEnabledVM = (e.Parameter as ViewModel);
}
private ViewModel isEnabledVM { get; set; }
private async void Button_Click(object sender, RoutedEventArgs e)
{
isEnabledVM.IsEnabled = false;
}

Related

data doesn't update on all bindings

I have two Windows, my MainWindow and a CounterWindow; on the MainWindow is a button with a binding and on my CounterWindow is a label with the same binding
When data is retrieved, the Button does receive the new data, but the CounterWindow label doesn't update.
Note, it turns to 0 on initializing (so the Binding functions!(?))
public class CounterModel : INotifyPropertyChanged
{
public string CurrentCount {
get { return mCurrentCount; }
set
{
if (value == mCurrentCount) return;
mCurrentCount = value;
OnPropertyChanged();
}
}
public CounterModel() {
UpdateCounters();
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
string mCurrentCount;
public void UpdateCounters(int i = 0)
{
CurrentCount = i.ToString();
}
}
}
MainWindow codehbehind:
public MainWindow()
{
InitializeComponent();
CounterBtn.DataContext = cntMdl;
}
CounterModel cntMdl = new CounterModel();
CounterWindow CodeBehind:
public CounterWindow()
{
InitializeComponent();
DataContext = new CounterModel();
}
CounterWindow Xaml
<TextBlock Text="{Binding CurrentCount}" FontSize="900" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Consolas" Foreground="White" MouseDown="TextBlock_MouseDown"/>
what am I missing?
Do not create a new CounterModel instance for the CounterWindow. Remove
DataContext = new CounterModel();
from the CounterWindow constructor.
In case you are showing the CounterWindow from the Button's Click event handler, pass the current DataContext to the new window:
private void Button_Click(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
var window = new CounterWindow { DataContext = button.DataContext };
window.Show();
}

C# WPF Update two user controls using dependency property located in another project

I am trying to set a common dependency property to two different user controls in WPF.
I tried lots of solutions that I found but none of them worked.
So for the moment what I got is the following:
I have a class containing the common property which currently (after trying almost everything) looks this way:
namespace CommonProperties {
public class CommonProp : DependencyObject, INotifyPropertyChanged
{
public static readonly DependencyProperty IsTrueProperty =
DependencyProperty.Register("IsTrue", typeof(bool), typeof(CommonProp), new PropertyMetadata(false));
private bool _isTrue;
public bool IsTrue
{
get { return (bool)GetValue(IsTrueProperty); }
set { SetValue(IsTrueProperty, value); NotifyPropertyChanged("IsTrue"); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string nomPropriete)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(nomPropriete));
}
}}
I also have two user controls which looks like that: UC1:
<UserControl x:Class="ClassLibUC1.UC1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:CommonProperties;assembly=CommonProperties"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<Grid>
<TextBox x:Name="text1"
Width="254"
Height="23"
Margin="24,24,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Text="{Binding IsTrue}"
TextWrapping="Wrap" />
<Button Width="75"
Margin="70,68,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Click="Button_Click"
Content="Button" />
</Grid>
UC1 ViewModel:
namespace ClassLibUC1 {
public class ViewModelUC1 : INotifyPropertyChanged
{
CommonProp prop = new CommonProp();
public bool IsTrue
{
get { return prop.IsTrue; }
set { prop.IsTrue = value; NotifyPropertyChanged("IsTrue"); }
}
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Trigger the PropertyChanged event to update views.
/// </summary>
/// <param name="nomPropriete"></param>
public void NotifyPropertyChanged(string nomPropriete)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(nomPropriete));
}
}
UC1 Code:
public partial class UC1 : UserControl
{
ViewModelUC1 vm = new ViewModelUC1();
public UC1()
{
InitializeComponent();
this.DataContext = vm;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
CommonProp prop = new CommonProp();
if (vm.IsTrue)
{
vm.IsTrue = false;
}
else
{
vm.IsTrue = true;
}
}
}
The second user control is exactly the same. The problem is that when I click a button in the first or the second user control, it only updates the selected control and not both of them.. Any idea how can I implement a common property for both controls?
With Dependency property we cannot achieve this because Dependency property belongs to one instance, means if you have two instance of user control, updating DependencyProperty value of one control will never update DependencyProperty of other Control as it is a different instance all together.
But still we can achieve that requirement of updating Same value for all usercontrols of same type like yours. For that we have to do some modification in xaml.cs file like below.
/// <summary>
/// Interaction logic for UC1.xaml
/// </summary>
public partial class UC1 : UserControl
{
private static List<UC1> _allInstanceOfThisControl = new List<UC1>();
ViewModelUC1 vm = new ViewModelUC1();
public UC1()
{
InitializeComponent();
this.DataContext = vm;
_allInstanceOfThisControl.Add(this);
this.Unloaded += UC1_Unloaded;
}
private void UC1_Unloaded(object sender, RoutedEventArgs e)
{
_allInstanceOfThisControl.Remove(this);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (vm.IsTrue)
{
vm.IsTrue = false;
}
else
{
vm.IsTrue = true;
}
var _allInstanceOfThisControlExceptthis = _allInstanceOfThisControl.Where(s => s != this).ToList();
_allInstanceOfThisControlExceptthis.ForEach(s =>
{
(s.DataContext as ViewModelUC1).IsTrue = vm.IsTrue;
});
}
Hope this will help to achieve your requirement.

Binding ViewModel property to a View

I have the following (a base class for pages and a viewmodel class):
public class MySuperPage : Page {
public MySuperPageViewModel VM = new MySuperPageViewModel();
..........
..........
public class MySuperPageViewModel {
protected bool _ShowProgress = false;
public bool ShowProgress {
get { return _ShowProgress; }
set {
_ShowProgress = value;
OnPropertyChanged("ShowProgress");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string property) {
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
Then an actual page
public class MyPage : MySuperPage(){
public MyPage() : base() {
this.InitializeComponent();
}
}
The XAML is the following:
<my:MySuperPage
xmlns:my="using:MyNamespace"
x:Name="pageRoot"
x:Class="MyPages.MyPage"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
....>
<ProgressRing IsActive="{Binding VM.ShowProgress, ElementName=pageRoot}" ... />
If in the code-behind I do actions such as
this.VM.ShowProgress = true; // or false
the effects are not visible.
Instead, things work if I assign object 'VM' to DefaultViewModel (which is an ObservableCollection):
this.DefaultViewModel["VM"] = VM;
I.e., in this last case using {Binding DefaultViewModel.VM.ShowProgress, ElementName=pageRoot} I manage to have the progress ring reflect the state of the VM instance.
I feel to miss something.
Your ViewModel in your page must be implemented as a property to make the binding work.
Change
public MySuperPageViewModel VM = new MySuperPageViewModel();
to
private MySuperPageViewModel _vm = new MySuperPageViewModel();
public MySuperPageViewModel VM { get { return _vm; }}

Seleceted Value from a ListBox WPF .NET 3.5

I have a listbox in my WPF app. The definition is given below:
<ListBox Margin="17.493,33.32,22.491,26.656" Name="lstData"
PreviewMouseLeftButtonDown="ListBox_MouseDown"
IsTextSearchEnabled="False" />
In the code behind, I bind the ListBox to a List. When the value is selected from the List Box, in my code behind, I want to be able to retrieve that value. How do I do it? Sample C# code will be helpful.
Thanks.
You can just bind to an item in your code behind
Example:
<ListBox Margin="17.493,33.32,22.491,26.656" Name="lstData"
SelectionChanged="ListBox_selectionChanged"
IsTextSearchEnabled="False"
ItemsSource="{Binding MyItems}"
SelectedItem="{Binding MySelectedItem}"/>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private ObservableCollection<MyItemType> _myItems = new ObservableCollection<MyItemType>();
public ObservableCollection<MyItemType> MyItems
{
get { return _myItems; }
set { _myItems = value; }
}
private MyItemType _mySelectedItem;
public MyItemType MySelectedItem
{
get { return _mySelectedItem; }
set { _mySelectedItem = value; NotifyPropertyChanged("MySelectedItem"); }
}
private void ListBox_selectionChanged(object sender, SelectionChangedEventArgs e)
{
MessageBox.Show(_mySelectedItem);
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string p)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
}

Populate ListBox

I have a window with a textbox and a submit button. When pressing the submit button, the data in the textbox should populate into the listbox and be saved.
What's the best way of doing this? I tried a recommendation (using ObservableCollection) from an earlier question I had, but I can't seem to get it work. I have tried implementing it like this:
I created a class:
public class AccountCollection
{
private string accountName;
public string AccountName
{
get { return accountName; }
set { accountName = value; }
}
public AccountCollection(string accountName)
{
AccountName = accountName;
}
}
Assigned the binding in my XAML:
<ListBox ItemsSource="{Binding AccountName, Mode=TwoWay}" IsSynchronizedWithCurrentItem="True" Height="164" HorizontalAlignment="Left" Margin="12" Name="accountListBox" VerticalAlignment="Top" Width="161" SelectionChanged="accountListBox_SelectionChanged" />
...and finally, when a user clicks the submit button from another window that contains the Submit button and textbox:
private void okBtn_Click(object sender, RoutedEventArgs e)
{
BindingExpression expression = okBtn.GetBindingExpression(accountaddTextBox.Text);
expression.UpdateSource();
}
But alas, I'm getting nowhere. I get an error message at the GetBindingExpression section:
Argument 1: cannot convert from 'string' to 'System.Windows.DependencyProperty'
What's obvious to me here is that when I created the class I didn't specify anything about the account name from the textbox, so I don't even know if the class is correct.
I'm basically confused and don't know what to do. Any help would be appreciated...
MODEL
// the model is the basic design of an object containing properties
// and methods of that object. This is an account object.
public class Account : INotifyPropertyChanged
{
private string m_AccountName;
public event PropertyChangedEventHandler PropertyChanged;
public string AccountName
{
get { return m_AccountName;}
set
{
m_AccountName = value;
OnPropertyChanged("AccountName");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
ListBox XAML
<ListBox Name="MyAccounts" DisplayMemberPath="AccountName" />
CODE BEHIND
// create a collection of accounts, then whenever the button is clicked,
//create a new account object and add to the collection.
public partial class Window1 : Window
{
private ObservableCollection<Account> AccountList = new ObservableCollection<Account>();
public Window1()
{
InitializeComponent();
AccountList.Add(new Account{ AccountName = "My Account" });
this.MyAccounts.ItemsSource = AccountList;
}
private void okBtn_Click(object sender, RoutedEventArgs e)
{
AccountList.Add(new Account{ AccountName = accountaddTextBox.Text});
}
}
edit: added displaymemberpath on listbox xaml
Here is a Demo using MVVM approach
ViewModel
public class AccountListViewModel : INotifyPropertyChanged
{
ICommand AddAccountCommand {get; set;}
public AccountListViewModel()
{
AccountList = new ObservableCollection<string>();
AddAccountCommand= new RelayCommand(AddAccount);
//Fill account List saved data
FillAccountList();
}
public AddAccount(object obj)
{
AccountList.Add(AccountName);
//Call you Model function To Save you lIst to DB or XML or Where you Like
SaveAccountList()
}
public ObservableCollection<string> AccountList
{
get {return accountList} ;
set
{
accountList= value
OnPropertyChanged("AccountList");
}
}
public string AccountName
{
get {return accountName } ;
set
{
accountName = value
OnPropertyChanged("AccountName");
}
}
}
Xaml Binding
<ListBox ItemsSource="{Binding Path=AccountList}" Height="164" HorizontalAlignment="Left" Margin="12" Name="accountListBox" VerticalAlignment="Top" Width="161" />
<TextBox Text={Binding Path=AccountName}></TextBox>
<Button Command={Binding Path=AddAccountCommand}><Button>
Xaml.cs Code
# region Constructor
/// <summary>
/// Default Constructor
/// </summary>
public MainView()
{
InitializeComponent();
this.DataContext = new AccountListViewModel();
}
# endregion
The Implementation of INotifyPropertyChanged and forming porpeties is left upto you
Your ItemsSource for your ListBox is AccountName, which is only a string but not a collection.
You need to create a viewmodel (your datacontext for the view) like this:
public class ViewModel
{
public ViewModel()
{
Accounts = new ObservableCollection<string>();
}
public ObservableCollection<string> Accounts { get; set; }
}
Bind ItemsSource to Accounts property:
<ListBox ItemsSource="{Binding Accounts}" Height="164" HorizontalAlignment="Left" Margin="12" Name="accountListBox" VerticalAlignment="Top" Width="161" />
And then, in your click event handler of the button you can simple add the current value of the textbox to your collection:
private void okBtn_Click(object sender, RoutedEventArgs e)
{
Accounts.Add(accountaddTextBox.Text);
}
But don't forget to set the DataContext of your window to the class ViewModel.

Categories

Resources