C# WPF: Communication between UserControls und Windows - c#

Hi my Problem is I haven't any Idea how I send Data from my UserControls to other UserControls or Windows in my Project.
My Project is a .Net 7 WPF-Project.
I have one FilterControl where Checkboxes and/or Textboxes filtering a List. The List exists in this FilterControl.
And after this filtering I want to send die filtered List to an other UserControl to show the List.
Aside from that I want to send the List to an Window.
How can I do that?
This is the MainWindow
<Window x:Class="MyProject.MainWindow"
xmlns:FilterCtrl="clr-namespace:MyProject.FilterControl"
xmlns:ListCtrl="clr-namespace:MyProject.ListControl">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<FilterCtrl:FilterControl/>
<ListCtrl:ListControl/>
</Grid>
</Window>
The UserControls:
SubFilter
<UserControl x:Class="MyProject.SubFilter">
<UserControl.DataContext>
<local:SubFilterViewModel/>
</UserControl.DataContext>
<Grid>
<CheckBox Command="{Binding CheckBoxCommand1}" Content="FilterOption1" Checked="{Binding CheckBool1}">
<CheckBox Command="{Binding CheckBoxCommand2}" Content="FilterOption2" Checked="{Binding CheckBool2}">
</Grid>
</UserControl>
FilterControl
<UserControl x:Class="MyProject.FilterControl
xmlns:SubFilterCtrl="clr-namespace:MyProject.SubFilterControl">
<UserControl.DataContext>
<local:FilterViewModel/>
</UserControl.DataContext>
<Grid>
<SubFilterCtrl:SubFilterControl/>
<TextBox Command="{Binding TextBoxCommand}" Text="AnotherFilterOption">
</Grid>
</UserControl>
ListControl
<UserControl x:Class="MyProject.ListControl
xmlns:ListCtrl="clr-namespace:MyProject.ListControl">
<UserControl.DataContext>
<local:FilterViewModel/>
</UserControl.DataContext>
<Grid>
<ListView MaxHeight="500" ItemsSource="{Binding FilteredList}" SelectedItem="{Binding SelectedColumm}">
<ListView.View>
<GridView AllowsColumnReorder="true">
<GridViewColumn DisplayMemberBinding="{Binding Path=Name}" Header="Name" Width="200"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
I Use an Relay Command from this Side:
RelayCommand
The List for Filtering are simple Objects with some Properties. Here only Name.
With the SubFilter I want only filtering with Checkboxes, and want back a List with the booleans from the CheckBoxes
The FilterControl filtering with these List from SubFilter and his own FilterOptions.
The ListControl should only show the List.

Now I have this in my MainWindow.xaml:
<Window x:Class="MyProject.MainWindow"
xmlns:FilterCtrl="clr-namespace:MyProject.FilterControl"
xmlns:ListCtrl="clr-namespace:MyProject.ListControl">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<FilterCtrl:FilterControl DataContext:"{Binding Main}"/>
<ListCtrl:ListControl DataContext:"{Binding Main}"/>
</Grid>
</Window>
In the MainViewModel I have the Variable:
public MainViewModel Main {get { return this;}}
because I want to change the Datacontext if I have an other Window who uses there, but with other Design-Options

Related

C# WPF binding data in ListBox

i have a problem in WPF application with binding data in ListBox.
Here is me xaml code:
<Window x:Class="DatabaseBoozeWpf.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:DatabaseBoozeWpf"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="625">
<Grid>
<ListBox
Margin="10,124,0,10"
ItemsSource="{Binding Boozes}"
HorizontalAlignment="Left"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ItemTemplate="{Binding Boozes}"
Width="233">
</ListBox>
</Grid>
But if I open the program, it will show this kind on text. It should output the list of products.
You should have an ItemTemplate with a DataTemplate with elements that bind to the properties of the item class.
<ListBox ItemsSource="{Binding Boozes}" ...>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding YourProperty}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

WPF Passing DataSource into a UserControl

I have a very simple usercontrol:
<UserControl x:Class="PointOfSale.UserControls.HousesGrid"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<ItemsControl x:Name="LayoutRoot" ItemsSource ="{Binding PopularHouses}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="5"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton
Content="{Binding FormattedPanelTimeRemaining}"
Style="{StaticResource MetroToggleButtonStyle}"
Height="45"
Width="80"
VerticalAlignment="Center"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
As you can see the ItemSource property is bound to the PopularHouses property on the ViewModel of the parent. This works great. However, what I want to do is set the ItemSource of the LayoutRoot element to a different property at the point on the parent form where the control is inserted in the XAML.
The end result should then be multiple instances of this user control, bound to several different properties on the parent's datacontext.
Could someone explain how to implement this?
You just have to bind your UserControl's DataContext to the datacontext of the first ContentControl using RelativeSource.
DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type ContentControl}}}"
I have made the following sample:
The mainwindow XAML
<Window x:Class="WpfDataContext.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfDataContext"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<local:UserControl1/>
</Grid>
</Window>
We set its datacontext to Self just for the purpose of this sample. In codebehind we define a simple property to show how it works:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public string SomeString { get; set; } = "Hello";
}
Then, the usercontrol XAML:
<UserControl x:Class="WpfDataContext.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type ContentControl}}}">
<Grid>
<TextBlock Text="{Binding SomeString}"/>
</Grid>
</UserControl>
Note how we bind its DataContext property since this is the key.
I use a Textblock for simplicity, but the principle applies for your case also

Multiple usercontrol not reflected while setting DataTemplate to ViewModel in MVVM

I am trying to add two usercontrols in one view
usercontrol working fine which get call in constructor i am implementing INotifyPropertyChanged for 'SelectedViewModel'.
property get updated for second usercontrol but not reflected in view .
thanks in advance
<Window x:Class="MovieBookinGWithUserControl.View.StartupWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MovieBookinGWithUserControl.ViewModel"
xmlns:localview ="clr-namespace:MovieBookinGWithUserControl.View"
Title="StartupWindow" Height="AUTo" Width="Auto">
<Window.Resources>
<DataTemplate DataType="{x:Type local:LoginWIndowViewModel}">
<localview:LoginWindow></localview:LoginWindow>
</DataTemplate>
<DataTemplate DataType="{x:Type local:MovieInfoViewModel }">
<localview:MovieInfo ></localview:MovieInfo>
</DataTemplate>
</Window.Resources>
<Grid>
<DockPanel LastChildFill="True">
<StackPanel x:Name="navigation" DockPanel.Dock="Left" Width="Auto">
</StackPanel>
<ContentControl x:Name="Pages" DockPanel.Dock="Right" Content="{Binding SelectedViewModel,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</DockPanel>
</Grid>
</Window>

WPF UserControl not rendering. UserControl is instantiated using DataTemplates

I have a user control that I`m trying to show via data templates. Unfortunately, the control never shows. Here's the DataTemplate for it:
<DataTemplate x:Key="listViewTemplate">
<ctrls:SpecialControl/>
</DataTemplate>
If I put regular controls inside those DataTemplate tags, I can see them. My SpecialControl however, won't show. Here's the xaml file for my SpecialControl:
<UserControl x:Class="CustomControls.SpecialControl"
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"
mc:Ignorable="d">
<StackPanel>
<CheckBox Content="Hello World" />
<Button >
<TextBlock Text="Goodbye world"/>
</Button>
</StackPanel>
</UserControl>
For some reason, this control is invisible at run time. If I put them directly into the template, I'll see them. I know I could just do that, but I want to do something more complex with this class, using databinding, and custom behavior. I tried using Snoop, and I can see my SpecialControl in there somewhere, with a ContentPresenter that's not expandable: no sign of The checkbox or the button.
Edit:
Here is the View that is using the SpecialControl: I left out many of the templates I'm using, because I don't want this to be too crowded.
<UserControl x:Class="Tools.EditorWindow"
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:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
xmlns:ctrls="clr-namespace:CustomControls"
xmlns:local="clr-namespace:Tools"
mc:Ignorable="d"
x:Name="This">
<UserControl.Resources>
<!--More templates -->
<DataTemplate x:Key="groupBoxTemplate" >
<ctrls:SpecialGroupBox Header="{Binding Path=Title}" Margin="2" DockPanel.Dock="Top">
<ItemsControl ItemsSource="{Binding guiItemsList}" ItemTemplateSelector="{DynamicResource guiTemplateSelector}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel>
<!-- Set up the width of the individual items based on how many columns we are supposed to have and what the adjusted width of the wrapPanel is. This way the 4th item will be placed on the 2nd row if the ColumnCount is 3. -->
<WrapPanel.ItemWidth>
<MultiBinding Converter="{StaticResource itemWidthConverter}">
<Binding Path="ColumnCount"/>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</WrapPanel.ItemWidth>
</WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ctrls:SpecialGroupBox>
</DataTemplate>
<DataTemplate x:Key="listViewTemplate">
<ctrls:SpecialControl/>
</DataTemplate>
<local:GuiTemplateSelector
... <!--More templates -->
GroupBoxTemplate="{StaticResource groupBoxTemplate}"
SpecialTemplate="{StaticResource listViewTemplate}"
x:Key="guiTemplateSelector"/>
</UserControl.Resources>
<DockPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto" Grid.Row="1">
<StackPanel Name="rootPanel" DockPanel.Dock ="Top" Width="Auto" Height="Auto">
<ItemsControl ItemsSource="{Binding guiItemsList}" ItemTemplateSelector=" {StaticResource guiTemplateSelector}">
</ItemsControl>
</StackPanel>
</ScrollViewer>
</DockPanel>
</UserControl>
If you're wondering what the SpecialGroupBox does, it holds other controls, positioning them a certain way. There are a few of them in this window, and they work. It is inside of one of these SpecialGroupBoxes that my SpecialControl is supposed to appear.
Does your UserControl have a corresponding .xaml.cs file? This problem seems to happen when it doesn't.
If you're using Visual Studio, try copying all the XAML from your UserControl, then deleting it from your project, adding a new UserControl (with the same name as before), then pasting your content back into the XAML file. This will ensure that you have the correct .xaml.cs file set up.
See this answer.
In your post you didn't mention how you are using the listViewTemplate . if your using inside listview/listbox you can try like this it will load the user control:
<ListView ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate >
<ContentControl ContentTemplate="{StaticResource listviewDataTemplate}" Content="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

DataTemplate View Renders but collection data does not

I am brand new to XAML, WPF and data binding so this might be a dumb question. I have a VM, AllTransactionViewModel with a collection of PurchaseTransactions. I have a view, via a Resource Dictionary, that renders each PurchaseTransaction in the collection in a ListView. I can get the View to render in the main window but I the data does not populate.
View - AllTransactionsView.Xaml:
<UserControl x:Class="BudgetApp.Views.AllTransactionsView"
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"
mc:Ignorable="d" d:DesignWidth="300" Height="97">
<UserControl.Resources>
<CollectionViewSource
x:Key="AllTrans"
Source="{Binding Path=AllTransactions}"/>
</UserControl.Resources>
<ListView
DataContext="{StaticResource AllTrans}"
ItemsSource="{Binding}" >
<ListView.View>
<GridView>
<GridViewColumn
Header="Name"
DisplayMemberBinding="{Binding Path=Name}"
Width="Auto"/>
<GridViewColumn
Header="Transaction Type"
DisplayMemberBinding="{Binding Path=TransactionType}" />
<GridViewColumn
Header="Amount"
DisplayMemberBinding="{Binding Path=Amount}"
/>
</GridView>
</ListView.View>
</ListView>
DataTemplate in MainWindowResoures.Xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:BudgetApp.ViewModels"
xmlns:vw="clr-namespace:BudgetApp.Views">
<DataTemplate x:Key="allTransTemplate" DataType="{x:Type vm:AllTransactionViewModel}">
<vw:AllTransactionsView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:TransactionViewModel}">
<vw:TransactionView />
</DataTemplate>
MainWindow.XAML:
<Window x:Class="BudgetApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:BudgetApp.ViewModels"
xmlns:vw="clr-namespace:BudgetApp.Views"
Title="MainWindow" Height="590.717" Width="767.194">
<Window.Resources>
<ResourceDictionary Source="MainWindowResources.xaml"/>
</Window.Resources>
<Grid>
<ContentControl
Content="{Binding AllTransactions}"
ContentTemplate="{StaticResource allTransTemplate}">
</ContentControl>
</Grid>
Finally, the AllTransactionViewModel class:
class AllTransactionViewModel: ViewModelBase
{
private BudgetEntities _context;
public AllTransactionViewModel()
{
_context = new BudgetEntities();
AllTransactions = new ObservableCollection<TransactionViewModel>();
GetAllTransactions();
}
public void GetAllTransactions()
{
foreach (var transaction in _context.PurchaseTransactions)
{
AllTransactions.Add(new TransactionViewModel
(
transaction.TransactionDate,
transaction.TransactionType.Description,
transaction.Name,
transaction.Memo,
(double)transaction.Amount,
transaction.IsApproved,
transaction.PurchaseType.Description
)
);
}
}
public ObservableCollection<TransactionViewModel> AllTransactions { get; private set; }
}
What am I doing wrong here?
First, when working with CollectionViewSource the binding (on ListView) should be:
ItemsSource="{Binding Source={StaticResource AllTrans}}"
You don't need the data context in this case. If you have more code than shown, and you actually need data context then leave items source as original and instead change data context:
DataContext="{Binding Source={StaticResource AllTrans}}"
The reason for the "weird" binding use is that you actually need CollectionViewSource.View as the items source. Binding has a special treatment when the source object is CVS and it gets the view automatically. StaticResource doesn't have the special treatment, and you can't use {StaticResource AllTrans.View} since it means to get the key in property View of AllTrans type, a type that doesn't exist.
[As a side note, maybe DataContext="{StaticResource AllTrans}" ItemsSource="{Binding View}" will work, never tried it]
The above should fill the items, but I'm not sure what will happen with the conflict of a data template with data type TransactionViewModel and the fact that you use DisplayMemberBinding on your columns. This might mess the items, but you still should be able to see that there are some items in the list view.

Categories

Resources