Xaml UWP buttons hide/show not working using INotifyPropertyChanged - c#

When i press the button the appbarbutton and slider doesnt hide.
When i debug i can confirm the "Collapse or Visible" is been notified.
Not sure what mistake i do. Please help to fix the issue.
I am building for Universal Windows Platform (UWP) for xbox one.
<Page
x:Class="AvProStreaming.MainPage"
IsTabStop="false"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:AvProStreaming"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="RosyBrown">
<SwapChainPanel x:Name="DXSwapChainPanel">
<Grid x:Name="ExtendedSplashGrid" Background="#FFFFFF">
<Image x:Name="ExtendedSplashImage" Source="Assets/SplashScreen.png" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
<Slider x:Name="slider" Background="Cyan" HorizontalAlignment="Stretch" Margin="10,444,10,0" VerticalAlignment="Top" Height="46"
Visibility="{Binding IsHide}" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="150" >
<AppBarButton Foreground="Cyan" Icon="Back" Name="Backward" Label="Back" Click="MenuItem_Selected"
Visibility="{Binding IsHide}" Margin="30"/>
<AppBarButton Foreground="Cyan" Icon="Play" Name="Play" Label="Play" Click="MenuItem_Selected"
Visibility="Collapsed" Margin="30"/>
<AppBarButton Foreground="Cyan" Icon="Pause" Name="Pause" Label="Pause" Click="MenuItem_Selected"
Visibility="{Binding IsHide}" Margin="30"/>
<AppBarButton Foreground="Cyan" Icon="Forward" x:Name="Forward" Label="Forward" Click="MenuItem_Selected"
Visibility="{Binding IsHide}" Margin="30"/>
</StackPanel>
</SwapChainPanel>
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
private WinRTBridge.WinRTBridge _bridge;
private SplashScreen splash;
private Rect splashImageRect;
private WindowSizeChangedEventHandler onResizeHandler;
private Visibility _IsHide;
public Visibility IsHide
{
get { return _IsHide; }
set
{
_IsHide = value;
OnPropertyChanged("IsHide");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}......
private void MainPage_KeyDown(object sender, KeyRoutedEventArgs e)
{
Debug.WriteLine("Keydown");
if (!App.IsXbox())
e.Handled = true;
if (e.OriginalKey == Windows.System.VirtualKey.GamepadMenu)
{
Debug.WriteLine("GamepadView button clicked");
IsHide = Visibility.Collapsed;
}
}

Bindings without explicitly specified source object require that the target element's DataContext (or that of one of its parent elements) is set to an instance of the class the owns the binding source property.
So adding DataContext = this; to the constructor fixed the issue.

Related

How to use popup within a tabitem to show that tab contents is loading in wpf mvvm?

I'm using tabitem which contains a popup to show that data is loading from API .
The problem is the popup shows over the window, and it disappears whenever another tab is selected even though the data is still loading.
Is it possible for popup to be shown within the tab like other controls? and keep doing what it's doing whether the containing tab is selected or not?
what control do you suggest to use instead of popup if it's not the right one for this case?
Here is an example to explain:
ViewModel:
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
private bool showPopUp;
public bool ShowPopUp
{
get { return showPopUp; }
set
{
showPopUp = value;
OnPropertyChanged(nameof(ShowPopUp));
}
}
}
Code behind:
public partial class MainWindow : Window
{
MainWindowViewModel model = new MainWindowViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = model;
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
//loading data
model.ShowPopUp = true;
await Task.Delay(100000);
model.ShowPopUp = false;
}
}
XAML:
<TabControl x:Name="tc">
<TabItem x:Name="tab1" Header="Tab1">
<TabItem.Content>
<Grid>
<Popup
Name="popUp1"
StaysOpen="True"
IsOpen="{Binding ShowPopUp, Mode=OneWay,
UpdateSourceTrigger=PropertyChanged}"
AllowDrop="True" Placement="Center"
Height="90" Width="135">
<Grid Background="LightGray">
<TextBlock Text="Loading ..." Margin="32" FontSize="16" />
</Grid>
</Popup>
<Button Height="30" Width="100" Content="Show popup" Click="Button_Click"/>
</Grid>
</TabItem.Content>
</TabItem>
<TabItem
x:Name="tab2"
Header="Tab2">
</TabItem>
</TabControl>

C# WPF Update Status bar text and progress from another window

I have a Main window named "wpfMenu" With a status bar which contains a text block and progress bar. The status bar needs to be updated from methods which are running on separate windows launched from the Main window (only one window open at any time).
Preferably I would like to pass the min, max, progress, text values to a class called "statusUpdate" to update the progress but i have no idea where to begin and any examples of updating progress bars I've come across are running on the same window.
Here is my code for the Status bar so far
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Custom="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon" x:Class="Mx.wpfMenu"
Title="Mx - Menu" Height="600" Width="1000" Background="#FFF0F0F0" Closed="wpfMenu_Closed">
<Grid>
<StatusBar x:Name="sbStatus" Height="26" Margin="0,0,0,0" VerticalAlignment="Bottom" HorizontalAlignment="Stretch">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem>
<TextBlock Name="sbMessage" Text="{Binding statusUpdate.Message}"/>
</StatusBarItem>
<StatusBarItem Grid.Column="1">
<ProgressBar Name="sbProgress" Width="130" Height="18" Minimum="0" Maximum="100" IsIndeterminate="False"/>
</StatusBarItem>
</StatusBar>
</Grid>
The code for my class is
public class statusUpdate : INotifyPropertyChanged
{
private string _message;
public event PropertyChangedEventHandler PropertyChanged;
public statusUpdate()
{
}
public statusUpdate (string value)
{
this._message = value;
}
public string Message
{
get { return _message; }
set
{
_message = value;
OnPropertyChanged("Message");
}
}
void OnPropertyChanged(string _message)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(_message));
}
}
}
There are several steps to this, but they're all well documented elsewhere. It might seem like a complex process, but it's something you'll do over and over in WPF.
You're right to store all the settings in a class. However this class needs to implement INotifyPropertyChanged and raise a PropertyChanged event in every property setter.
using System.ComponentModel;
public class StatusUpdate : INotifyPropertyChanged
{
private string message;
public event PropertyChangedEventHandler PropertyChanged;
public StatusUpdate()
{
}
public string Message
{
get { return this.message; }
set
{
this.message = value;
this.OnPropertyChanged("Message");
}
}
void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then you can make it a public property of your code-behind class, and bind your progress bar properties to it.
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
public StatusUpdate Status { get; set; } = new StatusUpdate();
private void PlayCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
public void PlayCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
this.Status.Message = "Play";
}
public void StopCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
this.Status.Message = "Stop";
}
}
Then you can pass a reference to the same class to the child forms, and when they set any of the properties, WPF will catch the event and update the GUI.
Let me know if you can't find an example for any of those steps.
Here's a version of your XAML with the binding and buttons I used for the above example:
<Window x:Class="WpfProgressBar.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"
xmlns:local="clr-namespace:WpfProgressBar"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.CommandBindings>
<CommandBinding Command="Play" Executed="PlayCommand_Executed" CanExecute="PlayCommand_CanExecute" />
<CommandBinding Command="Stop" Executed="StopCommand_Executed" />
</Window.CommandBindings>
<Grid>
<StackPanel>
<Button Content="Play" Command="Play" />
<Button Content="Stop" Command="Stop" />
</StackPanel>
<StatusBar Height="26" Margin="0,0,0,0" VerticalAlignment="Bottom" HorizontalAlignment="Stretch">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem>
<TextBlock Text="{Binding Status.Message, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, NotifyOnSourceUpdated=True}"/>
</StatusBarItem>
<StatusBarItem Grid.Column="1">
<ProgressBar Width="130" Height="18" Minimum="0" Maximum="100" IsIndeterminate="False"/>
</StatusBarItem>
</StatusBar>
</Grid>
</Window>
NB, I wouldn't normally do command bindings like this, but didn't want to get into the complications of adding RelayCommand

I need to open an Usercontrol in the main Window from another Usercontrol

Basically I have this Usercontrol, which is a main menu, with a new game button, a load button, and a setting button.
I need this to open when I start it up, but more importantly when hit new game button I need the main menu to be replaced with another usercontrol.
I have been trying and look up stuff for hours and have not worked out how to yet, so I hope someone can tell me what I have been doing wrong. Here is my current code.
I've still very much a beginner at programming and using this as a way to get bigger, so sorry if I seem slow.
MainWindow XAML:
<Window.Resources>
<DataTemplate DataType="{x:Type local:MainInterfaceViewModel}">
<local:MainInterface/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Character_CreationViewModel}">
<local:Character_Creation/>
</DataTemplate>
</Window.Resources>
<Window.Background>
<ImageBrush ImageSource="pack://application:,,,/Pokemorph Island;component/images/cover1.jpg"/>
</Window.Background>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="535*"/>
<RowDefinition Height="36*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90*"/>
<ColumnDefinition Width="307*"/>
</Grid.ColumnDefinitions>
<DockPanel Grid.ColumnSpan="2" Grid.RowSpan="2">
<ContentControl x:Name="FullScreen" DockPanel.Dock="Right" Content="{Binding SelectedViewModel}"/>
</DockPanel>
<DockPanel Grid.Column="0" Grid.RowSpan="2">
<ContentControl x:Name="User" />
</DockPanel>
<Button Content=">>>" HorizontalAlignment="Left" Click="Change_Image_UP" Style="{StaticResource RoundCorner}" Margin="66,0,0,0" VerticalAlignment="Top" Width="51" Height="31" Foreground="White" FontSize="16" FontWeight="Bold" FontFamily="Rockwell Extra Bold" Grid.Row="1"/>
<Button Content="<<<" HorizontalAlignment="Left" Click="Change_Image_Down" Style="{StaticResource RoundCorner}" Margin="10,0,0,0" VerticalAlignment="Top" Width="51" Height="31" Foreground="White" FontSize="16" FontWeight="Bold" FontFamily="Rockwell Extra Bold" Grid.Row="1"/>
<Button Content="Image Source" HorizontalAlignment="Left" Click="Image_Source" Style="{StaticResource RoundCorner}" Margin="431,0,0,0" VerticalAlignment="Top" Width="84" Height="31" Foreground="White" Grid.Column="1" Grid.Row="1"/>
<Button Content="PATREON" HorizontalAlignment="Left" Click="Patreon_Link" Style="{StaticResource RoundCorner}" Margin="520,0,0,0" VerticalAlignment="Top" Width="84" Height="31" Foreground="White" Grid.Column="1" Grid.Row="1"/>
<Button Content="Button" Margin="0,507,0,0" VerticalAlignment="Top" Width="75" Command="{Binding MainCommand}"/>
<Button Content="Button" Margin="134,507,584,0" VerticalAlignment="Top" Width="75" Command="{Binding CharCreaCommand}" Grid.ColumnSpan="2"/>
</Grid>
MainWindow Code
public partial class MainWindow : Window
{
int cover = 1;
public MainWindow()
{
InitializeComponent();
this.DataContext = new NavigationViewModel();
//FullScreen.Content = new MainInterface();
}
private void Image_Source(object sender, RoutedEventArgs e)
{
if (cover == 1)
System.Diagnostics.Process.Start("---------");
if (cover == 2)
System.Diagnostics.Process.Start("---------");
}
private void Change_Image_UP(object sender, RoutedEventArgs e)
{
cover = cover + 1;
if (cover > 2)
cover = 1;
if (cover == 1)
{
this.Background = new ImageBrush(new BitmapImage(new Uri(#"pack://application:,,,/Pokemorph Island;component/images/cover1.jpg", UriKind.Absolute)));
}
else if (cover == 2)
{
this.Background = new ImageBrush(new BitmapImage(new Uri(#"pack://application:,,,/Pokemorph Island;component/images/cover2.png", UriKind.Absolute)));
}
}
private void Change_Image_Down(object sender, RoutedEventArgs e)
{
cover = cover - 1;
if (cover < 1)
cover = 2;
if (cover == 1)
{
this.Background = new ImageBrush(new BitmapImage(new Uri(#"pack://application:,,,/Pokemorph Island;component/images/cover1.jpg", UriKind.Absolute)));
}
else if (cover == 2)
{
this.Background = new ImageBrush(new BitmapImage(new Uri(#"pack://application:,,,/Pokemorph Island;component/images/cover2.png", UriKind.Absolute)));
}
}
private void Patreon_Link(object sender, RoutedEventArgs e)
{
System.Diagnostics.Process.Start("https://www.patreon.com/user?u=3253293");
}
}
Mainmenu Usercontrol
<Grid>
<Button Content="New Game" HorizontalAlignment="Left" Style="{StaticResource RoundCorner}" Margin="10,10,0,0" VerticalAlignment="Top" Width="138" Height="76" Background="#338B0000" Foreground="White" FontFamily="Segoe Print" FontSize="24" FontWeight="Bold" Command="{Binding CharCreaCommand}" CommandParameter="CharCrea"/>
<Button Content="Load Game" HorizontalAlignment="Left" Style="{StaticResource RoundCorner}" Margin="10,91,0,0" VerticalAlignment="Top" Width="138" Height="76" Background="#338B0000" Foreground="White" FontFamily="Segoe Print" FontSize="24"/>
<Label Content="Pokémorph Island" HorizontalAlignment="Left" Margin="103,313,0,0" VerticalAlignment="Top" Height="111" Width="616" Foreground="#CCFF00C5" FontWeight="Bold" FontFamily="Rage Italic" FontSize="80"/>
<Button Content="Settings" HorizontalAlignment="Left" Style="{StaticResource RoundCorner}" Margin="10,172,0,0" VerticalAlignment="Top" Width="138" Height="76" Background="#338B0000" Foreground="White" FontFamily="Segoe Print" FontSize="24"/>
</Grid>
The Current MVVM I've been trying to use
class NavigationViewModel : INotifyPropertyChanged
{
public ICommand MainCommand { get; set; }
public ICommand CharCreaCommand { get; set; }
private object selectedViewModel;
public object SelectedViewModel
{
get { return selectedViewModel; }
set { selectedViewModel = value; OnPropertyChanged("SelectedViewModel"); }
}
public NavigationViewModel()
{
MainCommand = new BaseCommand(OpenMain);
CharCreaCommand = new BaseCommand(OpenCharCrea);
}
private void OpenMain(object obj)
{
SelectedViewModel = new MainInterfaceViewModel();
}
private void OpenCharCrea(object obj)
{
SelectedViewModel = new Character_CreationViewModel();
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
public class BaseCommand : ICommand
{
private Predicate<object> _canExecute;
private Action<object> _method;
public event EventHandler CanExecuteChanged;
public BaseCommand(Action<object> method)
: this(method, null)
{
}
public BaseCommand(Action<object> method, Predicate<object> canExecute)
{
_method = method;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute == null)
{
return true;
}
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_method.Invoke(parameter);
}
}
WPF has a notoriously tough learning curve. Partly because the MVVM pattern is used and it requires a certain amount of lateral thinking.
If you're thinking "this is hard" then that's normal. You're not being slow.
You've got a mix of code there. Try and move towards binding everything and away from events.
I would also suggest you use the mvvmlightlibs framework. Right click project in solution explorer, choose manage nuget packages and add the package. Use relaycommand for most icommands. There's also a base viewmodel implements inotifypropertychange you can inherit viewmodels from. Unless you need to serialise them.
One way to do this is to host the usercontrol you intend switching out in a contentcontrol. Bind the content to a property in your viewmodel. You then set that to either of two viewmodels. I'm not sure what to call them, let's say Start and Game. So you'll have a StartView with your initial buttons in it and a GameView with the buttons they need during the game. You then have a startVM and GameVM viewmodels with commands which correspond to your buttons.
I think you nearly have the idea of that in your code but an example template might look like:
<DataTemplate DataType="{x:Type local:StartVM}">
<local:Start/>
</DataTemplate>
Those have scope. So you can put that in a resources for a window and it's the whole window or a grid and it's just that grid.
You can also put them in a resource dictionary, merge that resource dictionary in app.xaml and it affects everywhere in your app.
You then need your contentcontrol to bind it's content to a property which will give it that gamevm or starvm. You look like you have that. Sort of.
<ContentControl Content="{Binding CurrentViewModel}"
I've tried to explain all this stuff but I think this brings us to your problem.
You need a command which will set that SelectedViewModel property and what you have is just a method.
Here are some example relaycommands:
https://msdn.microsoft.com/en-gb/magazine/dn237302.aspx
Your layout also looks a bit odd.
I wouldn't use a dockpanel, I'd suggest just a grid.
Usually I'd expect a toolbar kind of deal to be a top narrow banner and some content underneath it.

MVVM Listbox in tab control is not updating

I'm struggling with update issue. I have tab control with the listbox binded to an Observable Collection
ListBox HorizontalAlignment="Center" Height="450" VerticalAlignment="Top" Width="250"
x:Name="LbxMenu" Background="{x:Null}" BorderBrush="{x:Null}"
ItemsSource="{Binding TestListsNames}" FontFamily="Segoe UI Semilight" FontSize="18"/>
view model:
private ObservableCollection<string> _testListsName;
public ObservableCollection<string> TestListsNames
{
get { return _testListsName; }
set{ _testListsName = value; }
}
After inserting entity to database there is an event which invokes TestListInitialize method in my ViewModel which should refresh collection and it works as I can see it in debugger. But listbox doesn't refresh and I have to restart application to see changes.
It worked great when it was in separate window but when I changed ui to tab control it doesn't.
Update function:
private void TestListNamesInitialize()
{
TestListsNames = db.GetTestListNamesFromDatabase();
if (TestListsNames.Count != 0) CanLoad = true;
}
Initial Window:
<Controls:MetroWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Test.View.InitialWindow"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:tabdata="clr-namespace:Test.View.TabItems"
Title="Testownik" Height="600" Width="900" ShowTitleBar="True" ResizeMode="NoResize" Icon="../GraphicResources/Icon.ico">
<Controls:MetroWindow.RightWindowCommands>
<Controls:WindowCommands>
<Button Content="settings" />
<Button>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="4 0 0 0"
VerticalAlignment="Center"
Text="about" />
</StackPanel>
</Button>
</Controls:WindowCommands>
</Controls:MetroWindow.RightWindowCommands>
<Controls:MetroAnimatedTabControl x:Name ="MainTabControl">
<TabItem Header="Learn" Width="280">
<tabdata:LearnTabItem/>
</TabItem>
<TabItem Header="Database" Width="280">
<tabdata:DatabaseTabItem/>
</TabItem>
<TabItem Header="Statistics" Width="299">
<tabdata:StatisticsTabItem/>
</TabItem>
</Controls:MetroAnimatedTabControl>
Code behind:
public partial class InitialWindow : MetroWindow
{
InitialWindowViewModel viewModel=new InitialWindowViewModel();
public InitialWindow()
{
InitializeComponent();
DataContext = viewModel;
}
}
}
DatabaseTabItem:
<UserControl x:Class="Test.View.TabItems.DatabaseTabItem"
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:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:tabData="clr-namespace:Test.View.TabItems"
Height="500" Width="900" Background="White" BorderBrush="Transparent">
<UserControl.Resources>
</UserControl.Resources>
<Grid>
<Controls:MetroAnimatedTabControl x:Name ="DatabaseTabControl" Grid.Column="0" TabStripPlacement="Left" >
<TabItem Header="Choose" Width="250" >
<tabData:ChooseFromDbTabItem/>
</TabItem>
<TabItem Header="Add" Width="250">
<tabData:AddToDbTabItem/>
</TabItem>
<TabItem Header="Remove" Width="250">
<tabData:DeleteFromDbTabItem/>
</TabItem>
</Controls:MetroAnimatedTabControl>
</Grid>
code behind:
DatabaseViewModel vm = new DatabaseViewModel();
public DatabaseTabItem()
{
InitializeComponent();
DataContext = vm;
}
}
ChooseFromDbTabItem:
<UserControl x:Class="Test.View.TabItems.ChooseFromDbTabItem"
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:Test.View.TabItems"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="650" Background="White" BorderBrush="Transparent">
<Grid>
<ListBox HorizontalAlignment="Center" Height="450" VerticalAlignment="Top" Width="250"
x:Name="LbxMenu" Background="{x:Null}" BorderBrush="{x:Null}"
ItemsSource="{Binding TestListsNames}" FontFamily="Segoe UI Semilight" FontSize="18"/>
</Grid>
code behind:
public partial class ChooseFromDbTabItem : UserControl
{
public ChooseFromDbTabItem()
{
InitializeComponent();
}
}
You have to rise PropertyChanged event for the reason you change your entire collection and not a single item (if you changed a single item that was updated through the Observable).
private ObservableCollection<string> _testListsName;
public ObservableCollection<string> TestListsNames
{
get { return _testListsName; }
set
{
if (_testListsName != value)
{
_testListsName = value;
NotifyPropertyChanged("TestListsNames");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
You are not raising the PropertyChanged event when replacing the list using the property setter. Generelly, try to make collection properties readonly to reduce the risk for these sort of errors. Instead, clear the list and repopulate it. This will make sure that the view is notified about any changes.
public class ViewModel
{
private readonly ObservableCollection<string> _testListsName;
public ObservableCollection<string> TestListsNames
{
get { return _testListsName; }
}
private void TestListNamesInitialize()
{
_testListsName.Clear();
foreach(string name in db.GetTestListNamesFromDatabase())
{
_testListsName.Add(name);
}
if (_testListsNames.Count != 0) CanLoad = true;
}
}
However, note that this will raise changed events on each item using the .Add() call. See here: Can I somehow temporarily disable WPF data binding changes?
Edit: from your updated code. It can also be seen that you do not set the DataContext on your ChooseFromDbTabItem. You need to bind the DataContext property to the view model that exposes the collection:
<TabItem Header="Choose" Width="250" >
<tabData:ChooseFromDbTabItem DataContext="{Binding}" />
</TabItem>

windows store apps How to bind visibility of an appbar item?

I have some problems with binding a visibility property of an appbar button.
I want to bind an appbar button visibility to another element visibility.
If the another element is visible - then the appbar is visible.
So here is my code:
<common:LayoutAwarePage.BottomAppBar>
<AppBar>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Visibility="{Binding ElementName=btnSave, Path=Visibility}"
Click="Edit_Click" />
...(more buttons)
</StackPanel>
</AppBar>
</common:LayoutAwarePage.BottomAppBar>
<Button Grid.Row="7" Grid.Column="0"
x:Name="btnSave"
Content="Save"
Style="{StaticResource EditModeButtonStyle}"
Click="Save_Click" />
I am changing the btnSave visibility in the code behind and no reaction in the appbar button's visibility. I have even tried to do the same binding with just a textblock, and it worked fine. I have also tried to use converter on the appbar (even thought I don't need) and I saw that the debugger was not reading the converter's methods. I saw some more people wrote similar appbar problems, but nothing of the answers is not helping me. Does someone know how can I do it? (I don't want to use code behind to change appbar visibility).
I suspect that appbar elements are not seeing the page's elements and hence element binding is not working. I would recommend you to use independent property which implements INotifyPropertyChanged interface. Bind that property to those elements for which you want to set the visibility.
C#
public sealed partial class BlankPage4 : Page, INotifyPropertyChanged
{
private Visibility _IsHide;
public Visibility IsHide
{
get { return _IsHide; }
set
{
_IsHide = value;
OnPropertyChanged("IsHide");
}
}
public BlankPage4()
{
this.InitializeComponent();
DataContext = this;
}
private void btnHideAll_Click(object sender, RoutedEventArgs e)
{
IsHide = Visibility.Collapsed;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
XAML
<Page.BottomAppBar>
<AppBar IsSticky="True" IsOpen="True">
<StackPanel Orientation="Horizontal">
<Button x:Name="btnHello" Visibility="{Binding IsHide}" Content="Hello" />
<TextBlock Visibility="{Binding IsHide}" Text="Hello" FontSize="20"/>
</StackPanel>
</AppBar>
</Page.BottomAppBar>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<Button x:Name="btnSave" Visibility="{Binding IsHide}" Content="Save" />
<Button Content="Hide All" Click="btnHideAll_Click" />
</StackPanel>
</Grid>

Categories