Upadate TreeView From Class .cs - c#

Good morning for all;
I have a TreeView in my Window WPF, I use DataBinding to cover my TreeView.
Now I have another Class MyDesign.cs , and I want to upade the itms of my TreeView from this Class.
here My code:
MainWindow.xaml:
<Window x:Class="TreeViewAndDataBanding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self="clr-namespace:TreeViewAndDataBanding"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ContextMenu x:Key="MyDesignContextMenu">
<MenuItem Header="Paste" Command="{x:Static ApplicationCommands.Paste}"/>
<MenuItem Header="Search" Command="{x:Static self:MyDesign.Search}"/>
</ContextMenu>
<self:test x:Key="test"/>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="24*"/>
<ColumnDefinition Width="23*"/>
</Grid.ColumnDefinitions>
<TreeView x:Name="MyToolBox" ItemsSource="{StaticResource test}" Grid.Column="1" >
<TreeView.ItemTemplate>
<DataTemplate>
<TreeViewItem Header="All Cars">
<TreeViewItem Header="{Binding Path= Voiture}">
<TreeViewItem Header="{Binding Path=Vitesse}"></TreeViewItem>
</TreeViewItem>
</TreeViewItem>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<s:MyDesign Focusable="true" x:Name="MyDesigner"
Background="{StaticResource WindowBackgroundBrush}"
Margin="10" FocusVisualStyle="{x:Null}"
ContextMenu="{StaticResource MyDesignContextMenu}" Grid.Coulum="0"/>
</Grid>
</Window>
MenuItem.cs
namespace TreeViewAndDataBanding
{
public class MenuItem
{
private string _Voiture;
private string _Vitesse;
public MenuItem( string Voiture,string Vitesse)
{
this._Voiture = Voiture;
this._Vitesse = Vitesse;
}
public string Voiture
{
get { return _Voiture; }
}
public string Vitesse
{
get { return _Vitesse; }
}
}
}
test.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace TreeViewAndDataBanding
{
public class test : ObservableCollection<MenuItem>
{
public test()
{
Add(new MenuItem("Rapide", "Ferrari F430"));
}
}
}
And here My class MyDesign.Command.Cs, I want to be able to update my treeView in this Class (in method Search)
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace TreeViewAndDataBanding
{
public class MyDesign
{
public static RoutedCommand Search = new RoutedCommand();
public MyDesign()
{
this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste, Paste_Executed));
this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste, Search_Executed));
}
private void Search_Executed(object sender, ExecutedRoutedEventArgs e)
{
// d'ici je veux modifier mon TreeView
/******************************************************************************************/
/****** ici je veux modifier et mettre a jour mon Treeview dans l'interface *************/
/****************************************************************************************/
}
private void Paste_Executed(object sender, ExecutedRoutedEventArgs e)
{
}
}
}
Can You help me please,?? any ideas??

Doing this MVVM style is much cleaner, easier to maintain, and makes WPF make a lot more sense. An example (I've renamed a few things as my French is well. non-existent)
Create a ViewModel:
public class ViewModel {
public ObservableCollection<CarType> CarTypes { get; private set; }
public ViewModel() {
CarsTypes = new ObservableCollection<CarType>();
var sportsCars = new CarType("Sports cars");
sportscars.Cars.Add(new Car() { Make = "Ferrari", Model = "F430" });
CarTypes.Add(sportsCars);
}
}
And your View:
<Window ...
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<Window.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Cars}" DataType="{x:Type local:CarType}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:Car}">
<StackPanel>
<TextBlock Text="{Binding Make}"/>
<TextBlock> - </TextBlock>
<TextBlock Text="{Binding Model}"/>
</DataTemplate>
</Window.Resources>
<TreeView ItemsSource="{Binding CarTypes}"/>
</Window>
Please note that I typed above directly into SO, so I haven't compiled it. I may contains a few errors. But as you can see, using MVVM, this is very little code.
Now you can just add new instances to the Collection on the ViewModel, and your UI will update. Commands can be implemented on the ViewModel using RelayCommands.

Related

Bind controls to a stackpanel in winui3

i'm making in a music player program, and now I need to add a page to show the playlist's detail, such as the musics and the music's artists in the playlist.I'm going to make some musics' card and add them to a stackpanel.
I have achieved this by getting this panel object and calling its add function, but can I achieve it through data binding?
This is the way i used before
<StackPanel x:Name="PanelMusics" />
PanelMusics.Children.Add(...);
You should try using ListView or ItemsRepeater instead of StackPanel.
This is a simple example how to use ListView with the help of the CommunityToolkit.Mvvm NuGet package.
MusicItem.cs
namespace MusicCardsSample;
public class MusicItem
{
public string Title { get; set; } = string.Empty;
public string Artist { get; set; } = string.Empty;
}
MainPageViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;
namespace MusicCardsSample;
// The "CommunityTookit.Mvvm" needs this class to be "partial".
public partial class MainPageViewModel : ObservableObject
{
// The "CommunityTookit.Mvvm" creates
// an UI-interactable property "MusicItems" for you.
[ObservableProperty]
private ObservableCollection<MusicItem> musicItems = new();
// The "CommunityTookit.Mvvm" creates
// an "AddMusicItemCommand" command for you.
[RelayCommand]
private void AddMusicItem(MusicItem item)
{
musicItems.Add(item);
}
}
MainPage.xaml.cs
using Microsoft.UI.Xaml.Controls;
namespace MusicCardsSample;
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private MainPageViewModel ViewModel { get; } = new();
}
MainPage.xaml
<Page
x:Class="MusicCardsSample.MainPage"
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:local="using:MusicCardsSample"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Grid RowDefinitions="Auto,*">
<StackPanel
Grid.Row="0"
Orientation="Horizontal">
<TextBox
x:Name="TitleTextBlock"
PlaceholderText="Title" />
<TextBox
x:Name="ArtistTextBlock"
PlaceholderText="Artist" />
<Button
Command="{x:Bind ViewModel.AddMusicItemCommand}"
Content="Add">
<Button.CommandParameter>
<local:MusicItem
Title="{x:Bind TitleTextBlock.Text, Mode=OneWay}"
Artist="{x:Bind ArtistTextBlock.Text, Mode=OneWay}" />
</Button.CommandParameter>
</Button>
</StackPanel>
<ListView
Grid.Row="1"
ItemsSource="{x:Bind ViewModel.MusicItems, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:MusicItem">
<!--You can design your music cards here.-->
<StackPanel Orientation="Vertical">
<TextBlock
FontSize="9"
Text="{x:Bind Artist}" />
<TextBlock Text="{x:Bind Title}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Page>

WPF Combobox event does not fire (using MVVM and Expression.Blend)

I am really fairly new to WPF and have just wrapped my head around MVVM / Expression.Blend.
I am trying to use the Combobox "SelectedIndexChanged" event with InvokeCommandAction, binding to a command specified in the ViewModel.
However, the code in the command is never executed (the value myvalue is never updated).
What am I doing wrong here?
XAML:
<UserControl x:Class="GDX.UI.Views.AnalyseView"
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:i1="http://schemas.microsoft.com/xaml/behaviors"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:local="clr-namespace:GDX.UI.Views"
mc:Ignorable="d"
Height="720" Width="1210">
<Control.Resources>
<ResourceDictionary Source="pack://application:,,,/GDX.UI;component/ResourceDictionary/ResourceDictionary.xaml"/>
</Control.Resources>
<materialDesign:Card Margin="15,15,15,15" Grid.Column ="0" Grid.Row="0" Grid.RowSpan="6" Grid.ColumnSpan="2">
<ScrollViewer Grid.Row="0" Grid.RowSpan="5" Grid.Column="0" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Hidden">
<ItemsControl ItemsSource="{Binding buildingComponents}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="10">
<TextBlock Margin="10" Text="{Binding Path=UIName}" FontWeight="Bold"/>
<ComboBox
ItemsSource="{Binding Path=ConstructionOptions}"
SelectedItem="{Binding Path=Construction}"
HorizontalAlignment="Center"
Style="{StaticResource MaterialDesignOutlinedComboBox}"
Width="256"
Height="50"
BorderBrush="Red"
materialDesign:HintAssist.Hint="Baukonstruktion">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedIndexChanged">
<i:InvokeCommandAction Command="{Binding SetBuildingComponentConstruction}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</materialDesign:Card>
ViewModel:
using GDX.IO.Schemas;
using GDX.IO.Statics;
using GDX.MVVM;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace GDX.ViewModel.ViewModels
{
public class AnalyseViewModel : BaseViewModel
{
public ObservableCollection<BuildingComponent> buildingComponents { get; set; }
public double myvalue { get; set; }
public ICommand SetBuildingComponentConstruction { get; set; }
public AnalyseViewModel()
{
this.buildingComponents = new ObservableCollection<BuildingComponent>();
if (Building.BuildingComponents.Count != 0) //if contains elements
{
foreach (BuildingComponent bcomp in Building.BuildingComponents)
{
this.buildingComponents.Add(bcomp);
}
}
this.SetBuildingComponentConstruction = new RelayCommand(this.setBuildingComponentConstruction);
this.myvalue = 0;
}
public void setBuildingComponentConstruction()
{
myvalue += 1;
}
}
}
Looks like the SetBuildingComponentConstruction method is defined on AnalyseViewModel, but where you are binding in the itemstemplate the datacontext would be a BuildingComponent. You may have to "walk" up to the datacontext of your UserControl.
How do I use WPF bindings with RelativeSource?
Looking at the XAML Binding Failures tab in VS while debugging may also provide you with some direction.
Try
Command="{Binding DataContext.SetBuildingComponentConstruction,
RelativeSource={RelativeSource AncestorType=ComboBox}}"

C# WPF ListView control - Problem with binding data

I'm having some trouble binding data to a ListView control. I watched many tutorials where it seems like they did it the way I did here with either binding to a collection or a class that had a collection of items.
When I add the cars in this example nothing is added to the listview control. Anything obvious I have missed here? I have checked that the cars are added to the collection during runtime.
The car class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarClasses
{
internal class Car
{
string _brand = "";
string _model = "";
public Car(string brand, string model)
{
_brand = brand;
_model = model;
}
public string Brand
{
get { return _brand; }
set { _brand = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
}
}
MainWindow.xaml:
<Window x:Class="GridViewListView.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:GridViewListView"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="600">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"></ColumnDefinition>
<ColumnDefinition Width="2*"></ColumnDefinition>
<ColumnDefinition Width="7*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListView x:Name="lvCarList" ItemsSource="{Binding CarCollection }" Grid.Column="2" Width="200" Height="250" SelectionMode="Single" BorderThickness="3" BorderBrush="AliceBlue">
<ListView.Style>
<Style/>
</ListView.Style>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="{Binding Brand}"></Label>
<Label Grid.Row="0" Grid.Column="1" Content="{Binding Model}"></Label>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel Grid.Column="0">
<TextBlock Text="Brand" Margin="10,10,0,0"></TextBlock>
<TextBlock Text="Model" Margin="10,10,0,0"></TextBlock>
</StackPanel>
<StackPanel Grid.Column="1" Margin="0,0,0,0">
<TextBox Name="txtBrand" HorizontalAlignment="Left" Width="100" Margin="10,10,0,0"></TextBox>
<TextBox Name="txtModel" HorizontalAlignment="Left" Width="100" Margin="10,10,0,0"></TextBox>
<Button Name="btnAdd" Content="Add" Margin="10, 10,10,10" Click="btnAdd_Click"></Button>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using CarClasses;
namespace GridViewListView
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
///
public partial class MainWindow : Window
{
List<Car> CarCollection = new List<Car>();
public MainWindow()
{
InitializeComponent();
}
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
Car newCar = new Car(txtBrand.Text, txtModel.Text);
CarCollection.Add(newCar);
txtBrand.Text = "";
txtModel.Text = "";
}
}
}
You should/need to specify the DataContext.
And you need to make the Car's collection a public property. It's currently a field.
And also it should be an ObservableCollection, because it's changed at runtime and changes should be displayed in the UI automatically.
public partial class MainWindow : Window
{
public ObservableCollection<Car> CarCollection { get; } = new ObservableCollection<Car>();
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
}
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
Car newCar = new Car(txtBrand.Text, txtModel.Text);
CarCollection.Add(newCar);
txtBrand.Text = "";
txtModel.Text = "";
}
}

Navigate ContentControl from inside a UserControl in MVVM

I'm trying to create a sort of ShellView without using thirdparty frameworks, and I'm doing trying to do it via. ContentControls and UserControls.
I can navigate/switch the UserControls that is showed inside the ContentControls as long as the commands are fired from outside the UserControls, but nothing is happening when I move the code inside a button in a UserControl.
Currently I'm having one MainWindow.XAML, where I have one ContentControl.
This ContentControl is hosting either a LoginWindowUserControl, or a UserWindowUserControl - I want to be able switch the UserControl from within one of the UserControls.
My MainWindow.XAML looks like this:
<Window x:Class="ModelHealthApplication.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:vms="clr-namespace:ModelHealthApplication.ViewModels"
xmlns:ia="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:views="clr-namespace:ModelHealthApplication.Views.UserControls"
xmlns:local="clr-namespace:ModelHealthApplication"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate DataType="{x:Type vms:CurrentWindowUserStateViewModel}">
<views:UserView />
</DataTemplate>
<DataTemplate DataType="{x:Type vms:LoginWindowViewModel}">
<views:LoginView />
</DataTemplate>
<vms:NavigationViewModel x:Key="nVm" />
</Window.Resources>
<ia:Interaction.Triggers>
<ia:EventTrigger EventName="Loaded">
<ia:InvokeCommandAction Command="{Binding Source={StaticResource nVm}, Path=OpenLoginWindowCommand}" />
</ia:EventTrigger>
</ia:Interaction.Triggers>
<Grid DataContext="{StaticResource nVm}">
<DockPanel>
<Button Content="Test" DockPanel.Dock="Left" Command="{Binding OpenUserWindowStateCommand}" />
<ContentControl x:Name="WindowUserState" Content="{Binding CurrentWindowUserState}" />
</DockPanel>
</Grid>
And my UserWindowUserControl looks like this:
<UserControl x:Class="ModelHealthApplication.Views.UserControls.UserView"
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:vms="clr-namespace:ModelHealthApplication.ViewModels"
xmlns:views="clr-namespace:ModelHealthApplication.Views.UserControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ModelHealthApplication.Views.UserControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<DataTemplate DataType="{x:Type vms:MyModelsViewModel}">
<views:MyModelsView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vms:MyAccountViewModel}">
<views:MyAccountView />
</DataTemplate>
<vms:NavigationViewModel x:Key="nVm" />
</UserControl.Resources>
<Grid>
<DockPanel DataContext="{StaticResource nVm}">
<Grid DockPanel.Dock="Top" Background="{StaticResource MainBlue}" Height="25">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Column="0">
<Button Content="My Models"
HorizontalAlignment="Center"
Command="{Binding OpenMyModelsCommand}"
Style="{StaticResource NavButtonStyle}"/>
<Button Content="My Account"
HorizontalAlignment="Center"
Command="{Binding OpenMyAccountCommand}"
Style="{StaticResource NavButtonStyle}"
/>
</StackPanel>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right" Grid.Column="1" Margin="0, 0, 10, 0">
<TextBlock VerticalAlignment="Center" Foreground="White">
<Run Text="Logged in as:" FontWeight="Bold"/>
<Run Text="{Binding LoggedInAs}" d:Text="TestUser" />
</TextBlock>
<TextBlock Margin="20, 0 ,0 ,0" Text="Log Out" VerticalAlignment="Center" TextDecorations="Underline" Foreground="{StaticResource ComplenetarySecondOrange}" Background="{DynamicResource MainBlue}" Cursor="Hand">
<TextBlock.InputBindings>
<MouseBinding Command="{Binding OpenLoginWindowCommand}" MouseAction="LeftClick" />
</TextBlock.InputBindings>
</TextBlock>
</StackPanel>
</Grid>
<ContentControl x:Name="Pages" Content="{Binding SelectedViewModel}" />
</DockPanel>
</Grid>
</UserControl>
When I press the "Log Out" button/textblock I want to navigate back to the login window, but I can only do this from buttons that exist outside the UserControl.
I've read several other post similar to this, but I haven't found a solution that fits my needs - I tried using RelativeSource but without success - maybe someone can see what I'm doing wrong.
I'm using a "NavigationViewModel" to hold the commands which as I mentioned, works fine outside the UserControls:
using ModelHealthApplication.Commands;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace ModelHealthApplication.ViewModels
{
public class NavigationViewModel : INotifyPropertyChanged
{
public ICommand OpenMyModelsCommand { get; set; }
public ICommand OpenMyAccountCommand { get; set; }
public ICommand OpenUserWindowStateCommand { get; set; }
public ICommand OpenLoginWindowCommand { get; set; }
private object currentWindowUserState;
public object CurrentWindowUserState
{
get { return currentWindowUserState; }
set
{
currentWindowUserState = value;
OnPropertyChanged("CurrentWindowUserState");
}
}
private object selectedViewModel;
public object SelectedViewModel
{
get { return selectedViewModel; }
set
{
selectedViewModel = value;
OnPropertyChanged("SelectedViewModel");
}
}
public NavigationViewModel()
{
OpenMyModelsCommand = new OpenMyModelsCommand(this);
OpenMyAccountCommand = new OpenAccountCommand(this);
OpenUserWindowStateCommand = new OpenUserWindowStateCommand(this);
OpenLoginWindowCommand = new OpenLoginWindowCommand(this);
}
public void OpenUserWindowState(object obj)
{
CurrentWindowUserState = new CurrentWindowUserStateViewModel();
}
public void OpenLoginWindow(object obj)
{
CurrentWindowUserState = new LoginWindowViewModel();
}
public void OpenMyModels(object obj)
{
SelectedViewModel = new MyModelsViewModel();
}
public void OpenMyAccount(object obj)
{
SelectedViewModel = new MyAccountViewModel();
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
}
Ended up solving this with a great tutorial from SingletonSean on Youtube.
Posting here if anyone comes across this, and has the same issue.
Singleton Sean MVVM Navigatoin

ViewModel issue

I need pop up a window which takes time. The button is in Pressed state until the new window is opened. Hence I want to add a wait indicator over the UI window after I click the button and before the the window opens. The code of ViewModel is correct because I referred to a sample code. But why there is no response after I click the button.
The project file URL
https://supportcenter.devexpress.com/attachment/file/5268961b-ce35-4e40-b7c1-e33bffab902b
MainWindow:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DevExpress.Xpf.Core;
namespace WaitIndicatorDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : DXWindow
{
public MainWindow()
{
InitializeComponent();
vm = new MainVM();
DataContext = vm;
}
MainVM vm;
private void buttonShow_Click(object sender, RoutedEventArgs e)
{
vm.IsBusy = !vm.IsBusy;
}
}
}
ViewMode:
using DevExpress.Mvvm;
namespace WaitIndicatorDemo
{
public class MainVM
{
private readonly ISplashScreenService _waitIndicatorService;
public virtual bool IsBusy { get; set; }
public MainVM()
{
_waitIndicatorService =
ServiceContainer.Default.GetService<ISplashScreenService>("WaitIndicatorService");
}
protected void OnIsBusyChanged()
{
if (IsBusy)
_waitIndicatorService.ShowSplashScreen();
else
_waitIndicatorService.HideSplashScreen();
}
}
}
Below is the XAML, the comment ones are the original sample code. The checkbox bind to IsBusy. The indicator pop up when the checkbox is checked. I now want to pop up after press the button.
<dx:DXWindow x:Class="WaitIndicatorDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
xmlns:waitIndicatorDemo="clr-namespace:WaitIndicatorDemo"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
WindowStartupLocation="CenterScreen" SnapsToDevicePixels="True"
Title="MainWindow" Height="350" Width="525">
<!--DataContext="{dxmvvm:ViewModelSource Type=waitIndicatorDemo:MainVM}"-->
<!--Title="MainWindow" Height="350" Width="525">-->
<Grid Margin="10">
<!--<dxe:CheckEdit Content="Is Busy" IsChecked="{Binding IsBusy}"
VerticalAlignment="Top" HorizontalAlignment="Left" />
<Button Content="Button1" IsEnabled ="{Binding IsBusy, Converter={dxmvvm:BooleanNegationConverter}}"
VerticalAlignment="Top" HorizontalAlignment="Center" Click="Button_Click"/>
<Button Content="Button2" IsEnabled="{Binding IsBusy, Converter={dxmvvm:BooleanNegationConverter}}"
VerticalAlignment="Top" HorizontalAlignment="Right"/>-->
<Button x:Name="buttonShow" Content="Show" HorizontalAlignment="Left" Height="35" Margin="50,70,0,0" VerticalAlignment="Top" Width="75" Click="buttonShow_Click" />
</Grid>
</dx:DXWindow>
You have a few mistakes in your code sample :
1- The method OnIsBusyChanged in your ViewModel is never called.
2- Your XAML doesn't declare any ISplashScreenService object in the Window behaviors, like a DXSplashScreenService for instance.
Here's how you can fix both of those issues.
First, fix the ViewModel.
public class MainVM
{
private readonly ISplashScreenService _waitIndicatorService;
private bool _isBusy;
public virtual bool IsBusy
{
get
{
return _isBusy;
}
set
{
_isBusy = value;
OnIsBusyChanged();
}
}
public MainVM()
{
_waitIndicatorService =
ServiceContainer.Default.GetService<ISplashScreenService>("WaitIndicatorService");
}
protected void OnIsBusyChanged()
{
_waitIndicatorService.SetSplashScreenState("Doing some work...");
if (IsBusy)
_waitIndicatorService.ShowSplashScreen();
else
_waitIndicatorService.HideSplashScreen();
}
}
Then, your XAML.
<dx:DXWindow x:Class="WaitIndicatorDemo.MainWindow"
<!-- ... -->
Title="MainWindow" Height="350" Width="525">
<dxmvvm:Interaction.Behaviors>
<dx:DXSplashScreenService x:Name="WaitIndicatorService">
<dx:DXSplashScreenService.ViewTemplate>
<DataTemplate>
<Grid>
<Border Background="LightGray" CornerRadius="5">
<Border BorderBrush="#FF0072C6" BorderThickness="1" Margin="15" CornerRadius="5">
<Grid>
<ProgressBar BorderThickness="0" Value="{Binding Progress}" Maximum="{Binding MaxProgress}" IsIndeterminate="{Binding IsIndeterminate}" Height="12" />
<TextBlock Text="{Binding State, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
</Border>
</Grid>
</DataTemplate>
</dx:DXSplashScreenService.ViewTemplate>
</dx:DXSplashScreenService>
</dxmvvm:Interaction.Behaviors>
<Grid Margin="10">
<!-- ... -->
</Grid>
</dx:DXWindow>
This code was mainly taken from the How to: Use DxSplashScreenService sample.

Categories

Resources