Data binding custom control with parent - wpf

I have a UserControl that contains a listbox.
On the parent window, I have this UserControl and a button.
Ideally I'd like to use the ChangePropertyAction behavior on the parents button, and tie it to the UserControl's listbox count.
The idea being that if there are no entries in the listbox inside the usercontrol, the button on the parent window is hidden. The listbox is bound to an observablecollection.
Do I create a DependencyProperty to do this? I'm not sure how to bind the listbox's count to this property though.
Thanks so much for any insight into the right way to do this.

You can use a ElementName Binding to reach the ListBox state from the Button. You then want to use a BooleanToVisibilityConverter to do the magic.
Like so:
<Window x:Class="NestedTreeTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="200" Width="300">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="boolToVisibilityConverter" />
</Window.Resources>
<StackPanel>
<Button Visibility="{Binding ElementName=myList, Path=HasItems, Converter={StaticResource boolToVisibilityConverter}}">
Text
</Button>
<ListBox x:Name="myList">
<!--<ListBoxItem>Item A</ListBoxItem>-->
</ListBox>
</StackPanel>
</Window>
comment out, or uncomment the ListBoxItems to see it working...

I ended up using the Messenger classes from the MVVM Futures project to let the UserControl's ViewModel signal other ViewModels of the change.
This let's multiple listeners monitor for the same changes, without the need for extra Dependency Properties.

Related

WP7 XAML Bind to property in parent

I'm writting an app in WP7 (Silverlight 3). I have a view model that looks like this
public class MainViewModel
{
public List<ActivityTypes> ActivityTypes{get;set;}
public RelayCommand LoadActivity{get;set;}
}
My pages datacontext is set to the view model and I have a listbox with it's item source set to the ActivityTypes collection. In the listbox I'm trying to render a list of buttons who's command is bound to the LoadActivity property on the viewmodel. RelayCommand is part of the MVVM Light toolkit in case you are wondering what it is.
The problem I am having is I can't find a way to bind my button command to the LoadActivity property as my listbox has it's itemsource set to the Activitytypes collection and this property is in the parent. I've read about FindAncester but it doesn't look like this is supported in Silverlight 3.
My XAML looks like this
<UserControl.Resources>
<DataTemplate x:Key="ActivityTypeListTemplate">
<StackPanel>
<Button Command="{Binding LoadActivity}"> <!--binding not found as we're in the collection-->
<TextBlock Text="{Binding Name}" FontSize="50"/>
</Button>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<ListBox Margin="0" ItemsSource="{Binding ActivityTypes}" ItemTemplate="{StaticResource ActivityTypeListTemplate}"/>
</Grid>
What's the best way to code something like this?
There is no "direct" way to do this. You can set the Buttons DataContext to your MainViewModel (preferably as a StaticResource link) and the it would work.
Take a look at Bind to parent object in xaml

RadBusyIndicator always selected when designer is clicked

I have a RadBusyIndicator on my UserControl like so:
<Grid>
<!-- Other Content -->
<t:RadBusyIndicator IsBusy="{Binding IsBusy}"></t:RadBusyIndicator>
</Grid>
And whenever I click in the design view it goes to the BusyIndicator.
I can set the Panel.ZIndex to be negative to select the "Other Content", but this will cause the RadBusyIndicator to be behind the "Other Content"
I tried using a binding for the ZIndex like so:
<t:RadBusyIndicator Panel.ZIndex="{Binding BusyZIndex}" IsBusy="{Binding IsBusy}"></t:RadBusyIndicator>
But it doesn't help.
So the question is:
How do I have the RadBusyIndicator on "Top" of all the "Other Content" but still be able to click(in the designer) and go to the xaml line for that control?
The BusyIndicator needs to be "on top" to be in front of the controls. That makes it also on top in the designer.
There may be better ways of solving this, but what comes into mind is to make the BusyPanel a Resource on the UserControl, and then add it in the Grid control OnApplyTemplate or Loaded by code.
Here is the UserControl's XAML.
<UserControl x:Class="WpfApplication2.UserControl1"
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:t="REFERENCE.TO.THE.RAD.ASSEMBLY"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<t:RadBusyIndicator x:Key="TheBusyIndicator" IsBusy="{Binding IsBusy}">
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<Button Content="Some content to the button"
Height="25"
Width="200"/>
</Grid>
</UserControl>
I have added the BusyIndicator as a Resource with the Key "TheBusyIndicator".
I have also added x:Name="LayoutRoot" to the Grid which will contain the BusyIndicator.
The Grid can of course have another name if it in fact is not the layout root control.
By adding the BusyIndicator to the Children collection last, it will appear in front of all other controls that are added by the markup code.
Here is the code
UserControl's Constructor:
public UserControl1()
{
this.Loaded += new RoutedEventHandler(UserControl1_Loaded);
}
The execting code:
private void UserControl1_Loaded(object sender, RoutedEventArgs e)
{
this.LayoutRoot.Children.Add(this.Resources["TheBusyIndicator"] as RadBusyIndicator);
}
I never use UserControls anymore, only CustomControls where the XAML goes to "Generic.xaml" and I have no editor to work in. So I have not seen this problem for a while.

How bind button inside user control to another ViewModel

I'm working on project that based on WPF and MVVM.
I have some UserControl (summaryView) which has DataContext to ViewModel(SummaryVM).
I want put a button in summaryView and set the button DataContex to another viewModel(MainWindowViewModel) but it's not working for me.
This is the NameSpace of the ViewModel
xmlns:vm="clr-namespace:ContentSync.ViewModel"
This is my button
<Button HorizontalAlignment="Left" Width="100" Height="30" Margin="0,20" DataContex=... Command="{Binding ModifyUserSettingsCommand}">Modify</Button>
The command ModifyUserSettingsCommand is located at MainWindowViewModel and the but I don't know how to bind it to my button. I think I need to set it`s DataContext but I didn't succeed in figuring out what is the right syntax
Thanks
Add to UserControl reousrces this:
<UserControl.Resources>
<vm:MainWindowViewModel x:Key="btnViewModel" />
</UserControl.Resources>
And with that way you must assign DataContext to Button:
DataContext="{StaticResource btnViewModel}"

Trigger Property on another WPF control event

Suppose I have a ListView and TextBox and they are located
in different containers in the same Window.
Selecting items in the listview I want the TextBox Text property to be updated
in accordance with the listview data bound selected item.
Is it possible in XAML?
Sure... Check this out
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<ListBox x:Name="lb">
<TextBlock Text="Hey"/>
<TextBlock Text="There"/>
</ListBox>
<TextBlock Text="{Binding SelectedItem.Text, ElementName=lb}"/>
</StackPanel>
</Page>
You can bind to SelectedItem. In this case, I'm cheating, because I know it's a TextBlock, but in the real world you'll have to write a DataTemplate (most likely).

Command Binding in UserControl used as ListBox.ItemTemplate

I have a Listbox with a UserControl as the DataTemplate. This UserControl has a Button to remove that item from the list.
<ListBox x:Name="FileList" ItemsSource="{Binding Files}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Views:FileItem/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The ItemsSource is defined as:
ObservableCollection<FileViewModel> m_fileViews = new ObservableCollection<FileViewModel>();
Here is the UserControl simplified:
<UserControl x:Class="Views.FileItem">
<Canvas x:Name="LayoutRoot">
<TextBlock x:Name="FileName" Text="{Binding FileName}" />
<Button Content="Remove"/>
</Canvas>
</UserControl>
When the user clicks the Remove button, it should remove this item from the ObservableCollection.
The problem is, the DataContext for each ListBoxItem is a different ViewModel than the ViewModel that holds the ObservableCollection.
I'm not sure how to bind the Remove button to an ICommand in the "parent" ViewModel. Any help would be appreciated. Thanks so much.
I would bind the button to an ICommand in the UserControl's ViewModel, then send a message across to the parent ViewModel using loosely-coupled messaging (available in most Mvvm frameworks, like MvvmFoundation)
Let the parent VM register for the 'remove me' message, and update the ObservableCollection accordingly...
Hope this helps :)

Resources