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>
Related
in my Shell view XAML
<Grid>
....///
<StackPanel x:Name="SettingsPanelIsVisible" Grid.Row="6" Grid.Column="6" Orientation="Vertical"
VerticalAlignment="Bottom" >
<Button x:Name="Button1" Content="Button 1"/>
<Button x:Name="Button2" Content="Button 2"/>
</StackPanel>
</Grid>
and in my ShellViewModel
....//
public bool SettingsPanelIsVisible { get; set; }
as I understood these should be bound and the visibility should be toggled by caliburn.Micro by setting or resetting the bool, however this is not working, even though the other components are seeming to work fine
hum i just read StackPanel have some convention name, you error is maybe coming from your definition of viewmodel class ( dont see the code):
you have to put in viewmodel: using Caliburn.Micro;
public class ShellViewModel:Screen or PropertyChangedBase
{
private bool _SettingsPanelIsVisible;
public bool SettingsPanelIsVisible
{
get => _SettingsPanelIsVisible;
set
{
_SettingsPanelIsVisible = value;
NotifyOfPropertyChange(() => SettingsPanelIsVisible);
}
}
:
}
this convention is ok with Grid or StackPanel and maybe WrapPanel.....
I have a ListView with ItemTemplate. I want to bind one control background in ItemTemplate to 2 properties, one of properties is in ItemsSource and onother one is in my page. since UWP has no multibinding support, I bind it to one property in ItemSource and for another property in my page I want to handle it in my code behind.
<ListView >
<ListView.ItemTemplate>
<DataTemplate>
<Border HorizontalAlignment="Stretch"
x:Name="myborder"
Padding="5,0,5,0"
Background="{Binding myProperty, Converter={StaticResource convertPropertyToBgColor },ConverterParameter=border}">
<StackPanel Padding="0,10,10,10"
Background="{Binding myProperty, Converter={StaticResource convertPropertyToBgColor},ConverterParameter=stack}">
<TextBlock Text="{Binding Text}">
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
in the convertPropertyToBgColor I get the brush from Resources.
and in code behind when my second desired property is changed I Change My resources. so the brush I have used from resources get changed and because of that I want to call that converter again to refresh Background, I called updateLayout but it doesn't refresh my ListView and it doesn't call myConvereter again. How can I force ListView to recreate or refresh Items that it has made?
Generally you class should implement INotifyPropertyChanged, then once you change the property, usually in its setter you also call OnPropertyChanged event which will update your UI. There are plenty examples of that, here is one.
The other way, may be to call Bindings.Update(), but normally you probably should use the method above.
To make my comments clearer - something like this is possible:
<StackPanel Orientation="Horizontal" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView x:Name="myList" Width="200">
<ListView.ItemTemplate>
<DataTemplate>
<Border HorizontalAlignment="Stretch"
x:Name="myborder"
Padding="5,0,5,0"
Background="{Binding Path=DataContext.MyProperty, ElementName=myList}">
<StackPanel Padding="0,10,10,10">
<TextBlock Text="{Binding}"/>
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
<x:String>Element 1</x:String>
<x:String>Element 2</x:String>
<x:String>Element 3</x:String>
</ListView>
<Button Content="Change" Click="Button_Click"/>
</StackPanel>
code behind:
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
void RaiseProperty(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
private SolidColorBrush myPropety = new SolidColorBrush(Colors.Red);
public SolidColorBrush MyProperty
{
get { return myPropety; }
set { myPropety = value; RaiseProperty(nameof(MyProperty)); }
}
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e) => MyProperty = new SolidColorBrush(Colors.Blue);
}
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.
I am using a frame to navigate through multiple pages. The window is a wrapper of sorts as it displays the header with the titles to the pages and I have the footer with the navigation controls (back, home, forward). However the first page to load is the login screen so I would like to hide/modify the elements in the header and footer. These items are a part of the main window and the pages are child elements of the main window. How would I access the main windows elements from the child pages? I've attempted to name the elements and using the FindName method from the child pages but it is not working. I have the home button (HomeButtonBorder) collapsed originally and would like to make it visible once the user has successfully logged in.
Here is the MainWindow Code
<Grid>
<!-- HEADER -->
<Grid x:Name="HeaderGrid" Style="{StaticResource HeaderGridStyle}">
<Rectangle x:Name="HeaderRectangle" Style="{StaticResource HeaderRectangleStyle}" />
<Image x:Name="HeaderLogo" Style="{StaticResource HeaderLogoStyle}" />
<!-- PAGE HEADER -->
<!-- TITLE -->
<Grid x:Name="HeaderTitleGrid" Style="{StaticResource HeaderTitleGridStyle}" >
<Label x:Name="HeaderTitleLabel"
Style="{StaticResource HeaderTitleStyle}"
Content="{Binding Path=Content.Title, ElementName=MainFrame}" />
<!-- END HEADER -->
<!-- MAIN -->
<Frame x:Name="MainFrame" NavigationUIVisibility="Hidden"/>
<!-- END MAIN -->
<!--NAVIGATION -->
<!-- Back Button -->
<Button Content="«" Click="Nav_BackButton_OnClick" HorizontalAlignment="Left"
Visibility="{Binding Path=CanGoBack, ElementName=MainFrame, Converter={StaticResource BoolToVis}}"
Style="{StaticResource NavigationButtonStyle}" />
<!-- Home Button -->
<Border x:Name="HomeButtonBorder" Style="{StaticResource HomeBorderStyle}" MouseUp="Nav_HomeButton_OnClick">
<Image x:Name="HomeImage" Source="/Images/HomeButton_250x250.PNG" Width="100" />
</Border>
<!-- Forward Button -->
<Button Content="»" Click="Nav_ForwardButton_OnClick" HorizontalAlignment="Right"
Visibility="{Binding Path=CanGoForward, ElementName=MainFrame, Converter={StaticResource BoolToVis}}"
Style="{StaticResource NavigationButtonStyle}"/>
</Grid>
Here is the Login Page code that is not successful (It runs on LoginPage loaded)
public _0_LoginPage()
{
InitializeComponent();
}
private void LoginLoad(object sender, RoutedEventArgs e)
{
var homeButton = FindName("HomeButtonBorder") as Border;
var homeImage = FindName("HomeImage") as Image;
if (homeButton == null || homeImage == null) return;
homeButton.Visibility = Visibility.Visible;
homeImage.Visibility = Visibility.Visible;
}
I tried to use a interface which will deal with hiding the Home button. Refer the below code.
MainWindow.xaml
<Window x:Class="SQ15Mar2015_Learning.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300">
<Grid>
<StackPanel>
<StackPanel Orientation="Horizontal">
<Button Content="Login" Click="Button_Click"></Button>
<Button Content="Home" Visibility="{Binding HomeVisibility, RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window}}"/>
</StackPanel>
<Frame x:Name="frm"></Frame>
</StackPanel>
</Grid>
MainWindow.cs
public partial class Window2 : Window, IHomeVisibility,INotifyPropertyChanged
{
public Window2()
{
InitializeComponent();
HomeVisibility = Visibility.Collapsed;
}
private Visibility homeVisibility;
public Visibility HomeVisibility
{
get { return homeVisibility; }
set { homeVisibility = value; OnPropertyChanged("HomeVisibility"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
frm.Navigate(new Login(this));
}
}
Interface
public interface IHomeVisibility
{
Visibility HomeVisibility { get; set; }
}
Login.xaml.cs
public partial class Login : Page
{
public Login(IHomeVisibility homeBtnVisiblity)
{
InitializeComponent();
homeBtnVisiblity.HomeVisibility = Visibility.Visible;
}
}
There are many ways of doing dealing it. I strongly suggest you to go through MVVM.
Hey Embarrassingly I have not been able to get two-way binding working from the examples I have found. Here is one of my dataTemplates.
<local:ChatRoomTemplateSelector.YourSelf>
<DataTemplate x:Name="YourSelf">
<StackPanel>
<Grid x:Name="YourSelfGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<UserControl Grid.Row="0">
<Path Data="" Fill="LawnGreen" StrokeThickness="0" Stretch="Fill" UseLayoutRounding="True"/>
</UserControl>
<TextBox Text="{Binding Path=Post}" IsReadOnly="{Binding readOnly}" FontSize="20" Margin="39,10" TextWrapping="Wrap" TextAlignment="Center"/>
</Grid>
<StackPanel Orientation="Horizontal">
<Path Data="" Fill="LawnGreen" StrokeThickness="0" Stretch="Fill" UseLayoutRounding="True" Margin="50,-1,0,0"/>
<TextBlock Text="{Binding Name}" FontWeight="Bold" FontSize="25" TextWrapping="Wrap"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</local:ChatRoomTemplateSelector.YourSelf>
The element I need to have two-way binding on is Text="{Binding Path=Post}". But cannot get it working. The longlistselector I have, has the itemsource set to:
System.Collections.ObjectModel.ObservableCollection<Data> source = new System.Collections.ObjectModel.ObservableCollection<Data>();
This source is then set to my Longlistselectors itemsource.
Where the Data class is:
public class Data : INotifyPropertyChanged
{
public string Name
{
get;
set;
}
private string _dl;
public string Post
{
get { return _dl; }
set
{
if (value != _dl)
{
_dl = value;
NotifyPropertyChanged("Post");
}
}
}
public string User
{
get;
set;
}
public bool readOnly
{
get;
set;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
This is What I have tried with no success. Hope you can help me with the tweak that gives me two-way binding for the Post, in Data.
Extra Info
I now tried the mode=TwoWay, and finally got that working. Code updated.
But now the update is only happening upon lostfocus. But I need the update of the variable to happen when text is inserted.
So I need to set UpdateSourceTrigger.
But what should this be set to?
Solution
<TextBox TextChanged="OnTextBoxTextChanged"
Text="{Binding MyText, Mode=TwoWay,
UpdateSourceTrigger=Explicit}" />
UpdateSourceTrigger = Explicit is a smart bonus here. What is it? Explicit: Updates the binding source only when you call the UpdateSource method. It saves you one extra binding set when the user leaves the TextBox.
In C#:
private void OnTextBoxTextChanged( object sender, TextChangedEventArgs e )
{
TextBox textBox = sender as TextBox;
// Update the binding source
BindingExpression bindingExpr = textBox.GetBindingExpression( TextBox.TextProperty );
bindingExpr.UpdateSource();
}:
If you want your TextBox to be two way binded, then you should use Text="{Binding Path=Post,Mode=TwoWay}"
Windows phone don't support UpdateSourceTrigger=PropertyChanged but you can find a way to do that here .
Or an alternative is to use the UpdateTextBindingOnPropertyChanged from the Prism library. You can just download the source code of the file I linked and set it in in xaml like this:
<TextBox ...>
<i:Interaction.Behaviors>
<prism:UpdateTextBindingOnPropertyChanged/>
</i:Interaction.Behaviors>
</TextBox>