Define Source one time and use it many times - wpf

Currently I am using the below code to Bind to the TextBlock to the Application Settings
<Grid DataSource="{Binding DataContext.CurrentPatient, RelativeSource={RelativeSource AncestorType={x:Type Page}}">
...
...
...
<TextBlock Text="{Binding Source={StaticResource Settings}, Path=Default.Test}" />
<TextBox Text="{Binding Source={StaticResource Settings}, Path=Default.CurrentValue}" />
<TextBlock Text="{Binding Source={StaticResource Settings}, Path=Default.NormalValue}" />
...
...
...
</Grid>
Now I don't want to type Source={StaticResource Settings} in all the textblocks.
In short I want Code-minification. I mean I want my code to be maintainable and reduced.

Try this
public class Mybinding : Binding
{
//Load only once and use every time :)
static object Settings = App.Current.Resources["Settings"];
public Mybinding()
{
Source = Settings;
}
}
<TextBlock Text="{local:Mybinding Path=Default.Test}" />
>Edit
<Application.Resources>
<ResourceDictionary>
<properties:Settings x:Key="Settings" />
</ResourceDictionary>
</Application.Resources>
local is the namespace of Mybinding. I havent tested it .But hope this will give you an idea.And am Expecting "Settings" is in App.xaml or in ResourceDictionary Merged to App.xaml

Add one more grid and use its DataContext:
<Grid DataContext={Binding Source={StaticResource Settings}}>
<TextBlock Text="{Binding Default.Test}" />
<TextBox Text="{Binding Default.CurrentValue}" />
<TextBlock Text="{Binding Default.NormalValue}" />
<Grid>

Related

MvvmCross: View inside another View (or the equivalent to a CaliburnMicro Conductor)

I am pretty new to MvvmCross and the mvvm pattern in general, so I started a small learning project and immidiatly ran into a wall. I based my application on the idea of having a MainView which contains a standard Menu and a child MvxWpfView. This ChildView should be a simple ReadMeView first, but on user input it should switch to an other View (the one with actual data on it). I already found a few articles about this issue but none of them worked or i wasn't able to follow.
My setup:
Core Library (.NET Standard 2.0)
Wpf app (.NET Core 3.1)
This is my MainViewModel with this users solution still implemented:
using MvvmCross.Commands;
using MvvmCross.ViewModels;
namespace puRGE.Core.ViewModels
{
public class MainViewModel : MvxViewModel
{
#region Fields -------------------------------------------------------------------------------------
private HomeViewModel m_homeViewModel = new HomeViewModel();
#endregion ------------------------------------------------------------------------ Fields endregion
#region Properties ---------------------------------------------------------------------------------
public HomeViewModel Home {
get => m_homeViewModel;
set => SetProperty(ref m_homeViewModel, value);
}
#endregion -------------------------------------------------------------------- Properties endregion
#region Constructors -------------------------------------------------------------------------------
public MainViewModel() { }
#endregion ------------------------------------------------------------------ Constructors endregion
#region Public methods -----------------------------------------------------------------------------
public override void Prepare()
{
Home = new HomeViewModel();
}
#endregion ---------------------------------------------------------------- Public methods endregion
}
}
This is the xaml part located inside my MainView (still part of this users solution):
<Menu>
<!-- Some MenuItems -->
</Menu>
<UserControl DataContext="{Binding Home, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
Vision VS. Reality
image of what I am trying to achieve
I also tried using the MvxContentPresentation attribute, but to be honest I lost myself somewhere in the MvvmCross Documentation and at this point I am almost stepping on my eye bags.
<local:HomeView/>
This doesn't work either. Bindings stop working this way even when the properties value get's set inside the ViewModels Prepare()method. I guess calling the View like this breaks some chain of events or something.
How do I place a View inside my MainView? Is this Child then able to navigate to another View and vice versa (following the Navigation Documentation)?
Edit_01102020:
A general Mvvm approach doesn't seem to work so far.
Edit_02102020:
Home can now navigate to SomeOtherViewModel and back. Still no clue how to contain this in my MainView.
In your MainView.xaml:
<Menu>
<!-- Some MenuItems -->
</Menu>
<UserControl DataContext="{Binding Home}">
<UserControl.Resources>
<DataTemplate DataType="{x:Type viewModels:ModelAViewModel}">
<local:ModelAView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:ModelBViewModel}">
<local:ModelBView />
</DataTemplate>
</UserControl.Resources>
<ContentPresenter Content="{Binding}" />
</UserControl>
Remember to Notify your changes in your HomeViewModel:
public void ActivateModelAViewModel()
{
HomeViewModel = Mvx.IoCProvider.Resolve<ModelAViewModel>();
//In your HomeViewModel property:
//RaisePropertyChanged(() => HomeViewModel);
}
public void ActivateModelBViewModel()
{
HomeViewModel = Mvx.IoCProvider.Resolve<ModelBViewModel>();
//In your HomeViewModel property:
//RaisePropertyChanged(() => HomeViewModel);
}
I have also found that the following alternatives also do the job (except for the first one, commented out):
<StackPanel>
<!--<TextBlock FontWeight="Bold">1. ContentPresenter - DataContext</TextBlock>
<ContentPresenter DataContext="{Binding ActiveViewModel}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>-->
<TextBlock FontWeight="Bold">2. ContentPresenter - Content</TextBlock>
<ContentPresenter Content="{Binding ActiveViewModel}" >
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
<TextBlock FontWeight="Bold">3. ContentControl - DataContext</TextBlock>
<ContentControl DataContext="{Binding ActiveViewModel}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</ContentControl.Resources>
<ContentPresenter Content="{Binding}" />
</ContentControl>
<TextBlock FontWeight="Bold">4. ContentControl - Content</TextBlock>
<ContentControl Content="{Binding ActiveViewModel}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
<TextBlock FontWeight="Bold">5. UserControl - DataContext</TextBlock>
<UserControl DataContext="{Binding ActiveViewModel}">
<UserControl.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</UserControl.Resources>
<ContentPresenter Content="{Binding}" />
</UserControl>
<TextBlock FontWeight="Bold">6. UserControl - Content</TextBlock>
<UserControl Content="{Binding ActiveViewModel}">
<UserControl.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</UserControl.Resources>
</UserControl>
<TextBlock FontWeight="Bold">7. MvxWpfView - DataContext</TextBlock>
<views:MvxWpfView DataContext="{Binding ActiveViewModel}">
<views:MvxWpfView.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</views:MvxWpfView.Resources>
<ContentPresenter Content="{Binding}" />
</views:MvxWpfView>
<TextBlock FontWeight="Bold">8. MvxWpfView - Content</TextBlock>
<views:MvxWpfView Content="{Binding ActiveViewModel}">
<views:MvxWpfView.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</views:MvxWpfView.Resources>
</views:MvxWpfView>
</StackPanel>
Some are just inherited from the others, eg. MvxWpfView : UserControl; UserControl : ContentControl, but not sure about ContentPresenter, which needs not to have the child <ContentPresenter Content="{Binding}" /> inside (since it is itself a ContentPresenter).
In my case ActiveViewModel, WorkWeekViewModel and WorkViewModel are instances of MvxViewModel; WorkWeekView and WorkView are instances of MvxWpfView.

Adding custom values to ComboBox with CompositeCollection

I'm new to WPF. I have a combobox which when choosing a value three other fields (AbbrBlock, MultiBrandSupplier, IgnoreNoCompetition) update along to show the correct relevant values according to the data source. No problem with this.
Issue arises when I try to add to the combobox a custom value, although the combobox shows all values correctly, the other fields don't change when changing the combobox's value.
Here's the working code (without the additional custom combobox value - stripped to the key pieces):
<Window.Resources>
<local:OrdersDataSet x:Key="ordersDataSet" />
<CollectionViewSource x:Key="caSuppliersViewSource" Source="{Binding CaSuppliers, Source={StaticResource ordersDataSet}}"/>
</Window.Resources>
...
<StackPanel DataContext="{StaticResource caSuppliersViewSource}">
<ComboBox Name="SupplierDropdown" DisplayMemberPath="SupplierName"
ItemsSource="{Binding Source={StaticResource ResourceKey=caSuppliersViewSource}}"/>
<TextBlock Name="AbbrBlock" VerticalAlignment="Center" Text="{Binding Abbr}"/>
<CheckBox Name="MultiBrandSupplier" IsChecked="{Binding MultiBrand}"/>
<CheckBox Name="IgnoreNoCompetition" IsChecked="{Binding IgnoreNoCompetition}"/>
</StackPanel>
Here's the code with the added custom value which shows correctly but the other fields don't update when changing the combobox value:
<Window.Resources>
<local:OrdersDataSet x:Key="ordersDataSet" />
<CollectionViewSource x:Key="caSuppliersViewSource" Source="{Binding CaSuppliers, Source={StaticResource ordersDataSet}}"/>
</Window.Resources>
...
<StackPanel DataContext="{StaticResource caSuppliersViewSource}">
<StackPanel.Resources>
<CompositeCollection x:Key="myCompositeCollection">
<CollectionContainer Collection="{Binding Source={StaticResource ResourceKey=caSuppliersViewSource}}" />
<ComboBoxItem Content="Add New..." />
</CompositeCollection>
</StackPanel.Resources>
<ComboBox Name="SupplierDropdown" DisplayMemberPath="SupplierName"
ItemsSource="{Binding Source={StaticResource myCompositeCollection}}"/>
<TextBlock Name="AbbrBlock" VerticalAlignment="Center" Text="{Binding Abbr}"/>
<CheckBox Name="MultiBrandSupplier" IsChecked="{Binding MultiBrand}"/>
<CheckBox Name="IgnoreNoCompetition" IsChecked="{Binding IgnoreNoCompetition}"/>
</StackPanel>
What am I missing here?
Looks like the ComboBox was updating caSuppliersViewSource's View.CurrentItem property (I think) to match its SelectedItem in your first snippet. In the second, the CollectionViewSource is buried inside a CompositeCollection so that doesn't happen any more. However, the ComboBox is still selecting an item, and you can just bind to that using ElementName. No need for setting the DataContext on the StackPanel with this version.
<StackPanel>
<StackPanel.Resources>
<CompositeCollection x:Key="myCompositeCollection">
<CollectionContainer Collection="{Binding Source={StaticResource ResourceKey=caSuppliersViewSource}}" />
<ComboBoxItem Content="Add New..." />
</CompositeCollection>
</StackPanel.Resources>
<ComboBox
Name="SupplierDropdown"
DisplayMemberPath="SupplierName"
ItemsSource="{Binding Source={StaticResource myCompositeCollection}}"
/>
<TextBlock
Name="AbbrBlock"
VerticalAlignment="Center"
Text="{Binding SelectedItem.Abbr, ElementName=SupplierDropdown}"
/>
<CheckBox
Name="MultiBrandSupplier"
IsChecked="{Binding SelectedItem.MultiBrand, ElementName=SupplierDropdown}"
/>
<CheckBox
Name="IgnoreNoCompetition"
IsChecked="{Binding SelectedItem.IgnoreNoCompetition, ElementName=SupplierDropdown}"
/>
</StackPanel>
You could also give eyour viewmodel a SelectedDBItem property of the same type as whatever caSuppliersViewSource contains, and bind ComboBox.SelectedItem to that. Then you could do this:
<TextBlock
Name="AbbrBlock"
VerticalAlignment="Center"
Text="{Binding SelectedDBItem}"
/>
But that's six dozen of one, half of another, or something -- unless you want to do something else with SelectedDBItem in your viewmodel, then it's handy.

WPF UserControl or ControlTemplate... (not sure)

I have a listbox where I have to add about 20 static custom items. All the items are based on the same template (something like that) :
<Border>
<StackPanel Orientation="Horizontal">
<Image Source="" Height="30" />
<TextBlock Text="" VerticalAlignment="Center" />
</StackPanel>
</Border>
I don't want to repeat that 20 times in the ListBox.Items I would like to have some kind of UserControl where I could do something Like the following where I could set some custom properties :
<ListBox>
<ListBox.Items>
<MyListBoxTemplate x:Name="Item1" ItemText="Item #1" ItemImageSource="/Image1.jpg" />
<MyListBoxTemplate x:Name="Item2" ItemText="Item #2" ItemImageSource="/Image2.jpg" />
...
</ListBox.Items>
</ListBox>
But I don't wan't to create a userControl just for that!!! Is there an easy way to put that template in the Window.Resources?
Thanks
If you are ONLY using it for that SPECIFIC listbox, you can just assign the ItemTemplate property. This will need to work in conjunction with a collection of custom objects defined in your resources somewhere else. This will save you from creating a custom UserControl, but you will need an object that can be defined in XAML and a list of them in XAML anyway. To be honest, creating a UserControl is relatively painless and may be easier, but it is possible without doing so.
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate TargetType="CustomObjectType">
<Border>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageSource}" Height="30" />
<TextBlock Text="{Binding TextContent}" VerticalAlignment="Center" />
</StackPanel>
</Border>
<DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
EDIT: If you are going to use it in more than one place, put the DataTemplate in your Application resources and ive it a key, then assign the ItemTemplate property to {StaticResource MyListBoxItemsTemplateKey}
Not my favorite approach since it uses the XmlDataProvider and XPath syntax (which I tend to always forget). But you can embed your static data as xml within your Window.Resources like so:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<XmlDataProvider x:Key="MyStaticData" XPath="StaticItems" >
<x:XData>
<StaticItems xmlns="">
<StaticItem>
<ItemText>Item #1</ItemText>
<ItemImageSource>/Image1.jpg</ItemImageSource>
</StaticItem>
<StaticItem>
<ItemText>Item #2</ItemText>
<ItemImageSource>/Image2.jpg</ItemImageSource>
</StaticItem>
</StaticItems>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<Grid>
<ListBox>
<ListBox.ItemsSource>
<Binding Source="{StaticResource MyStaticData}" XPath="StaticItem" />
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<Border>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding XPath=ItemImageSource}" Height="30" />
<TextBlock Text="{Binding XPath=ItemText}" VerticalAlignment="Center" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Then within your ListBox bind to the XmlDataProvider you specified and use the XPath notation within the bindings to drill down to the data you want the controls to bind to.
This site has a couple good examples too:
http://vbcity.com/blogs/xtab/archive/2010/12/24/more-xpath-examples-in-a-wpf-application.aspx
Hope this helps!

bind textblock to current listbox item in pure xaml

i have some data saved in a xml file.
Those will be displayed in a listbox.
Now, when i change the listbox Selectedindex, i would like to update the other information in the textblock based on the selectedindex.
is there any way to do this in pure xaml?
if not, how would i bind the Textblock to the selecteditem in the listbox ?
EDIT:
How would i navigate through the Data without using the listbox? i mean using a button to move to next item and other button to move backward..!!
any help is really appreciated..
<Window x:Class="WpfSingleInstance.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
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Cornsilk">
<StackPanel.Resources>
<XmlDataProvider x:Key="InventoryData" XPath="Inventory/Books">
<x:XData>
<Inventory xmlns="">
<Books>
<Book ISBN="0-7356-0562-9" Stock="in" Number="9">
<Title>XML in Action</Title>
<Summary>XML Web Technology</Summary>
</Book>
<Book ISBN="0-7356-1370-2" Stock="in" Number="8">
<Title>Programming Microsoft Windows With C#</Title>
<Summary>C# Programming using the .NET Framework</Summary>
</Book>
<Book ISBN="0-7356-1288-9" Stock="out" Number="7">
<Title>Inside C#</Title>
<Summary>C# Language Programming</Summary>
</Book>
</Books>
</Inventory>
</x:XData>
</XmlDataProvider>
</StackPanel.Resources>
<TextBlock FontSize="18" FontWeight="Bold" Margin="10"
HorizontalAlignment="Center">XML Data Source Sample</TextBlock>
<ListBox
Width="265" Height="98" x:Name="lbox" Background="Honeydew" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemsSource>
<Binding Source="{StaticResource InventoryData}"
XPath="*[#Stock='out'] | *[#Number>=8 or #Number=3]"/>
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="12" Foreground="Red">
<TextBlock.Text>
<Binding XPath="Title"/>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel DataContext="{StaticResource InventoryData}">
<TextBlock Text="{Binding XPath=Book/Title}"/>
<TextBox Margin="5,31,98,10" x:Name="textBoxMainDetail" Text="{Binding XPath=Book/Summary}" />
</StackPanel>
</StackPanel>
</Grid>
You could bind like this:
<TextBox Text="{Binding ElementName=lbox, Path=SelectedItem[Title].InnerText}" />
SelectedItem is an XmlElement.
EDIT: Here is a bit of sample code how to access the data of the XmlDataProvider in code behind and apply it as DataContent of a TextBox.
Change the TextBox.Text binding like this:
<TextBox x:Name="textBoxMainDetail" Text="{Binding Path=[Title].InnerText}" />
In code behind get the XML data from the XmlDataProvider and set the DataContext of the TextBox:
XmlDataProvider dataProvider = (XmlDataProvider)stackPanel.Resources["InventoryData"];
XmlElement books = (XmlElement)dataProvider.Document.SelectNodes(dataProvider.XPath)[0];
// set DataContext to an item from the child node collection
textBoxMainDetail.DataContext = books.ChildNodes[0];
Note that the StackPanel with the XmlDataProvider in its resource dictionary has now got a name. If this code shall run during application initialization (e.g. in Window constructor), the XmlDataProvider.IsAsynchronous property must be set to false.
You should now be able to change the DataContext to another indexed item of the books collection in a button click handler.
You need to set the SelectedValuePath as the 'Title' for your listbox. Then simply bind the your textBlock to the selectedValue of your listbox using elementName like this -
<ListBox Width="265" Height="98" x:Name="lbox" Background="Honeydew"
IsSynchronizedWithCurrentItem="True" SelectedValuePath="Title">
</ListBox>
<StackPanel DataContext="{StaticResource InventoryData}">
<TextBlock Text="{Binding Path=SelectedValue, ElementName=lbox}"/>
<TextBox Margin="5,31,98,10" x:Name="textBoxMainDetail" Text="{Binding XPath=Book/Summary}" />
</StackPanel>
</StackPanel>

Any way to reuse Bindings in WPF?

I'm getting to the point in a WPF application where all of the bindings on my controls are getting quite repetitive and also a little too verbose. Also if I want to change this binding I would have to change it in various places instead of just one.
Is there any way to write the source part of the binding once such as in a resource and then reuse it by referencing it with a more compact syntax. I've looked around for such capabilities but I haven't found it.
What I'm doing now
<StackPanel>
<ToggleButton x:Name="someToggleButton" />
<Button Visibility="{Binding ElementName=someToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}" />
<Grid Visibility="{Binding ElementName=someToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}" />
<TextBox Visibility="{Binding ElementName=someToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}" />
<CheckBox Visibility="{Binding ElementName=someToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}" />
</StackPanel>
What I want to be able to do (Pseudocode)
<StackPanel>
<StackPanel.Resources>
<Variable x:Name="someToggleButtonIsChecked"
Type="{x:Type Visibility}"
Value="{Binding ElementName=someToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}" />
</StackPanel.Resources>
<ToggleButton x:Name="someToggleButton" />
<Button Visibility="{VariableBinding someToggleButtonIsChecked}" />
<Grid Visibility="{VariableBinding someToggleButtonIsChecked}" />
<TextBox Visibility="{VariableBinding someToggleButtonIsChecked}" />
<CheckBox Visibility="{VariableBinding someToggleButtonIsChecked}" />
</StackPanel>
Is there any similar type of similar feature or technique that will allow me to declare the binding source once and then reuse it?
You can just bind someToggleButton's IsChecked property to a property on your viewmodel (the DataContext) and use that. It would look something like this:
<StackPanel>
<ToggleButton x:Name="someToggleButton" IsChecked="{Binding ToggleVisibility, Mode=TwoWay, Converter={StaticResource BoolToVisibilityConverter}}" />
<Button Visibility="{Binding ToggleVisibility}" />
<Grid Visibility="{Binding ToggleVisibility}" />
<TextBox Visibility="{Binding ToggleVisibility}" />
<CheckBox Visibility="{Binding ToggleVisibility}" />
</StackPanel>
This would require that your Window's DataContext has a property called ToggleVisibility of type Visibility.
EDIT:
To eleborate further, your viewmodel could look like this:
public class SomeViewModel : INotifyPropertyChanged
{
private Visibility toggleVisibility;
public SomeViewModel()
{
this.toggleVisibility = Visibility.Visible;
}
public Visibility ToggleVisibility
{
get
{
return this.toggleVisibility;
}
set
{
this.toggleVisibility = value;
RaisePropertyChanged("ToggleVisibility");
}
}
private void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
And you would then set an instance of it as the DataContext on the Window or even just on the StackPanel
Is there any way to write the source part of the binding once such as in a resource and then reuse it by referencing it with a more compact syntax.
Perhaps you can do that with PyBinding. I don't know the extent of its capabilities, but I use it all the time ot avoid type converters. Here is an example I use a lot.
Visibility="{p:PyBinding BooleanToVisibility(IsNotNull($[.InstanceName]))}"
BooleanToVisibility is a function I wrote in IronPython.
$[.InstanceName] binds to the InstanceName property of the current data-bound item.
EDIT: You can also use this to bind one UI's property to another's. Here is some info from the help file.
$[NameTextBlock.Text] - The text property of the element with x:Name equal to "NameTextBlock"
$[NameTextBlock] - An actual TextBlock instance, rather than one of its properties
$[{Self}] - Bind to your self. Equivalent to {Binding RelativeSource={RelativeSource Self}}
$[{Self}.Text] - The Text property off your self. Equivalent to {Binding Path=Text, RelativeSource={RelativeSource Self}}
http://pybinding.codeplex.com/
Untested Theory
<StackPanel>
<ToggleButton x:Name="someToggleButton" />
<Button Visibility="{p:PyBinding BooleanToVisibility($[someToggleButton.IsChecked])}" />
<Grid Visibility="{p:PyBinding BooleanToVisibility($[someToggleButton.IsChecked])}"/>
<TextBox Visibility="{p:PyBinding BooleanToVisibility($[someToggleButton.IsChecked])}"/>
<CheckBox Visibility="{p:PyBinding BooleanToVisibility($[someToggleButton.IsChecked])}"/>
</StackPanel>
Second Attempt
<StackPanel>
<ToggleButton x:Name="someToggleButton" />
<Button Name="myButton" Visibility="{p:PyBinding BooleanToVisibility($[someToggleButton.IsChecked])}" />
<Grid Visibility="{p:PyBinding $[myButton.Visibility]}"/>
<TextBox Visibility="{p:PyBinding $[myButton.Visibility]}"/>
<CheckBox Visibility="{p:PyBinding $[myButton.Visibility]}"/>
</StackPanel>
Just looking at the original code, you could group the necessary elements into their own container and then manage the container Visibility:
<StackPanel>
<ToggleButton x:Name="someToggleButton" />
<StackPanel Visibility="{Binding ElementName=someToggleButton, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}">
<Button />
<Grid />
<TextBox />
<CheckBox />
</StackPanel>
</StackPanel>
Actually, today I would do this with the VSM - have a state with the elements Visible and a state with them not Visible, then use two GoToState Behaviors on the Toggle button to set the state based on the button's toggle state.

Resources