ViewModel issue - c#

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.

Related

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 = "";
}
}

C#/WPF How to make close application button from a ViewModel

So I am new to the whole C#/WPF thing and was wondering how to make a button that when clicked will close the application.
I have tried numerous suggestions from google searches like:
Close Window from ViewModel
WPF Close window with MVVM from ViewModel class
https://web.csulb.edu/~pnguyen/cecs475/pdf/closingwindowmvvm.pdf
https://medium.com/#franklyndejesusmejia/close-a-window-from-viewmodel-using-wpf-and-mvvm-pattern-277ec7ef1805
https://social.msdn.microsoft.com/Forums/vstudio/en-US/17aabea0-4aca-478f-9205-fcd56080b22a/how-to-close-a-window-by-clicking-the-button-using-mvvm?forum=wpf
https://www.youtube.com/watch?v=U7Qclpe2joo&ab_channel=BrianLagunas
None of which seemed to help me out properly. Below I have provided the code I currently have that I made following a tutorial on ViewModel navigation. If more code is needed let me know.
Files:
File List
MainMenuViewModel:
using Creator.Commands;
using Creator.Stores;
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Input;
namespace Creator.ViewModels
{
class MainMenuViewModel : ViewModelBase
{
public ICommand NavigateItemCreateMenuCommand { get; }
public MainMenuViewModel(NavigationStore navigationStore)
{
NavigateItemCreateMenuCommand = new NavigateCommand<ItemCreateMenuViewModel>(navigationStore, () => new ItemCreateMenuViewModel(navigationStore));
}
}
}
MainMenuView: Quit button must close the application
<UserControl x:Class="Creator.Views.MainMenuView"
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:local="clr-namespace:Creator.Views"
mc:Ignorable="d"
d:DesignHeight="720" d:DesignWidth="1280">
<Grid Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<DockPanel Background="LightBlue" Grid.Row="1" Grid.Column="1" >
<StackPanel>
<Label Content="Main Menu" HorizontalAlignment="Center" VerticalAlignment="Stretch" FontWeight="Bold" FontFamily="Century Gothic" FontSize="24"/>
<Button Content="Create Item" FontWeight="Bold" FontFamily="Century Gothic" FontSize="18" Margin="20,0,20,5" Padding="0,5,0,5" Command="{Binding NavigateItemCreateMenuCommand}"/>
<Button Content="Quit" FontWeight="Bold" FontFamily="Century Gothic" FontSize="18" Margin="20,0,20,5" Padding="0,5,0,5" VerticalAlignment="Bottom"/>
</StackPanel>
</DockPanel>
</Grid>
</UserControl>
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;
namespace Creator
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
TL;DR:
I need to make the Quit button on MainMenuViewModel/MainMenuView to close the application.
Extend your ViewModel with QuitCommand and do bind it to the Button.
class MainMenuViewModel : ViewModelBase
{
public ICommand NavigateItemCreateMenuCommand { get; }
public ICommand QuitCommand { get; }
public MainMenuViewModel(NavigationStore navigationStore)
{
NavigateItemCreateMenuCommand = new NavigateCommand<ItemCreateMenuViewModel>(navigationStore, () => new ItemCreateMenuViewModel(navigationStore));
QuitCommand = new RelayCommand((par) => { Application.Current.Shutdown(); });
}
}
<Button Content="Quit" FontWeight="Bold" FontFamily="Century Gothic" FontSize="18" Margin="20,0,20,5" Padding="0,5,0,5" VerticalAlignment="Bottom" Command="{Binding QuitCommand}"/>
Find also implementation of RelayCommand in Why RelayCommand
You should use Command to close a running window in the ViewModel.
You can import the currently running MainWindow by handing over the parent control Window to the CommandParameter.
I made a sample for you by using MVVM.
I hope it helps you.
👉Github
Structure
MainMenuView.xaml
<Grid>
<Grid Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<DockPanel Style="{StaticResource MAIN.DOCK}">
<StackPanel>
<Label Style="{StaticResource MAIN.LABEL}"/>
<Button Style="{StaticResource BTN.CREATE}"/>
<Button Style="{StaticResource BTN.QUIT}"/>
</StackPanel>
</DockPanel>
</Grid>
</Grid>
MainMenuView.xaml.cs
public partial class MainMenuView : UserControl
{
public MainMenuView()
{
InitializeComponent();
DataContext = new MainMenuViewModel();
}
}
MainMenuViewModel
public class MainMenuViewModel
{
public ICommand QuitCommand { get; set; }
public MainMenuViewModel()
{
QuitCommand = new RelayCommand<object>(QuitApp);
}
private void QuitApp(object obj)
{
if (obj is Window window)
{
window.Close();
}
}
}
MainMenuResource
The whole resource source is in the Github.
<Style TargetType="{x:Type Button}" x:Key="BTN.QUIT">
<Setter Property="Command" Value="{Binding QuitCommand}"/>
<Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
<Setter Property="Content" Value="Quit"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontFamily" Value="Century Gothic"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Margin" Value="20 0 20 5"/>
<Setter Property="Padding" Value="0 5 0 5"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
</Style>
First i'll create an interface
public interface IClosable
{
Action Close { get;set; }
}
then you're viewmodel should implement this interface
MainWindowViewModel : ICloseable
{
public Action Close { get;set; }
//your code
}
then on the window
public partial class MainMenuView : Window
{
public MainMenuView()
{
InitializeComponent();
DataContext = new MainMenuViewModel();
if(DataContext is IClosable closable)
{
closable.Close += this.Close();
}
}
}
Also unhook the delegate before closing window.
Now invoking Close Action in viewmodel will close window.

How to stop Label from stacking in wpf

I am creating a program where if you click the button it adds a new label. However the problem is that when you click the add button the label keeps getting stack on top of eachother instead of being a list
Here is the code
c#
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;
namespace firstwpfapp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void addTask(object sender, RoutedEventArgs e)
{
String val = input.ToString();
Label todo = new Label();
todo.Content = val;
List.Children.Add(todo);
}
}
}
xaml
...
<Window x:Class="firstwpfapp.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:firstwpfapp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid Margin="-120,-142,0,0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0*"/>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="451*"/>
</Grid.ColumnDefinitions>
<StackPanel x:Name="Wrapper"Background="LightGray" Orientation="Horizontal"></StackPanel>
<TextBox x:Name="input" Grid.Column="2" HorizontalAlignment="Left" Height="31" Margin="106,198,0,0" TextWrapping="Wrap" Text="Enter here" VerticalAlignment="Top" Width="166"/>
<Button Content="Button" Grid.Column="2" HorizontalAlignment="Left" Margin="106,234,0,0" VerticalAlignment="Top" Width="166" Height="26" Click="addTask"/>
<Grid x:Name="List" Grid.Column="2" HorizontalAlignment="Left" Height="391" Margin="507,160,0,0" VerticalAlignment="Top" Width="385"/>
</Grid>
</Window>
the list keeps getting stack on top of another each time the button is pressed
You can go ahead and add your items to a ListView which will stack the items for you as well as include an ItemSource that we can bind to so it will create the rows for each new ToDo item for you:
Note: I have not tested the below; I'm on my Macbook.
Instead of your Wrapper StackLayout, replace it with:
<ListView Name="Wrapper" Grid.Row="0" Grid.ColumnSpan="3" ItemsSource="{Binding Tasks}" />
Now, create a new file called Task.cs which we will use when creating a new type of Task (add the below to the Task.cs file):
public class Task { public string task { get; set;} }
Have your MainWindow inherit from the INotifyPropertyChanged interface INotifyPropertyChanged
public partial class MainWindow : Window, INotifyPropertyChanged
Now update the rest of your code behind of MainWindow to:
private ObservableCollection<Task> _tasks;
//Tasks will store all of the tasks of type Task that we add to it
//as well as be bound to our ListView that will display whatever we add to our Tasks
public ObservableCollection<Task> Tasks
{
get
{
return _tasks;
}
set
{
if (value != _tasks)
{
_tasks = value;
OnPropertyChanged("Tasks");
}
}
}
//Here we implement OnPropertyChanged so our ObservableCollection can be notified
//whenever we have a new task added to or removed from Tasks (this is created when we implement INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
//Create a new Task and add it to our Tasks any time the addTask button is clicked
private void addTask(object sender, RoutedEventArgs e)
{
Tasks.Add(new Task(input.Text));
}
Replace the Grid
<Grid x:Name="List" Grid.Column="2" HorizontalAlignment="Left" Height="391" Margin="507,160,0,0" VerticalAlignment="Top" Width="385"/>
with a StackPanel:
<StackPanel x:Name="List" Grid.Column="2" HorizontalAlignment="Left" Height="391" Margin="507,160,0,0" VerticalAlignment="Top" Width="385"/>
Adding child elements to a grid stacks them on top of each other (as you have noticed)
A StackPanel adds new child elements below (or after) the previous child element.
Try this ...................
XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel VerticalAlignment="Top" HorizontalAlignment="Center"
Orientation="Horizontal"
Margin="0,50,0,0">
<TextBox Name="Input"
Width="300"
VerticalAlignment="Center"
HorizontalAlignment="Left" />
<Button Name="AddBtn"
Content="Add"
Margin="20,0,0,0"
VerticalAlignment="Center"
Width="100"
Click="AddBtn_Click"/>
</StackPanel>
<ListView Name="ItemListView"
ItemsSource="{Binding Path=LabelItems, Mode=OneWay}"
Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="20"/>
</Grid>
C# code:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private ObservableCollection<string> _labels = new ObservableCollection<string>();
public ObservableCollection<string> LabelItems
{
get { return _labels; }
set { _labels = value; RaisePropertyChanged(); }
}
private void AddBtn_Click(object sender, RoutedEventArgs e)
{
if(Input.Text != "" && Input.Text != null)
{
LabelItems.Add(Input.Text);
}
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged([CallerMemberName]string name = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}

Progress bar isn't updating on custom splash screen

So I'm trying to have a splash screen that has a progress bar that increments as my application loads. Obviously I've had to edit code to remove any IP, thankfully most of this is simple enough that none of it really matters. But any help would be greatly appreciated.
Failed Solution 1
Here is the code for my application block:
public class App : Application
{
public void Run()
{
bool isLoaded = false;
ProgressSplashScreen splashScreen = new ProgressSplashScreen(() => { isLoaded = true; });
splashScreen.Show();
SpinWait.SpinUntil(() => isLoaded);
_bootStrapper = new BootStrapper(splashScreen);
_bootStrapper.Run();
splashScreen.Close();
}
}
Here is the code for my splash screen XAML:
<Window x:Class="Application.ProgressSplashScreen"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Splash" BorderBrush="Transparent"
AllowsTransparency="True"
Icon="../../Resources/Icons/Icon.ico"
WindowStartupLocation="CenterScreen"
WindowStyle="None" Width="640" Height="520"
Background="Transparent" Name="SplashWindow" Topmost="True" >
<Grid>
<StackPanel Orientation="Vertical" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch">
<Image Source="../../Resources/Images/splash.jpg" Height="480" Width="640"/>
<Grid>
<ProgressBar Name="SplashProgress" Height="20" Minimum="0" Maximum="100"
BorderBrush="Transparent" />
<Label Name="SplashMessage" VerticalAlignment="Bottom"
HorizontalAlignment="Center"/>
</Grid>
</StackPanel>
</Grid>
</Window>
And the Code Behind for the Splash Screen XAML:
using System;
using System.Threading;
using System.Windows;
namespace Application
{
public partial class ProgressSplashScreen : Window
{
private SynchronizationContext _synchContext;
public ProgressSplashScreen(Action isLoaded)
{
this.Loaded += (sender, args) => isLoaded();
InitializeComponent();
_synchContext = SynchronizationContext.Current;
}
public void SetProgress(double progress, string message)
{
_synchContext.Send((state) =>
{
SplashProgress.Value = progress;
SplashMessage.Content = message;
}, null);
}
}
}
And Finally the BootStrapper Class that I am trying to make the update calls from:
namespace Application
{
internal sealed class BootStrapper : BaseMefBootstrapper
{
private ProgressSplashScreen _splash;
public BootStrapper(ProgressSplashScreen splashScreen)
{
_splash = splashScreen;
}
public void Run()
{
// removed do stuff code here
_splash.SetProgress(10, "Loading stuff...");
// removed do stuff code here
_splash.SetProgress(40, "Loading stuff...");
// removed do stuff code here
_splash.SetProgress(80, "Loading stuff...");
// removed do stuff code here
_splash.SetProgress(90, "Loading stuff...");
// removed do stuff code here
_splash.SetProgress(100, "Loading stuff...");
}
}
}
And so far my screen just sits there with an empty progress bar...
Failed Solution 2
ps... I've also tried
using System;
using System.Threading;
using System.Windows;
namespace Application
{
public partial class ProgressSplashScreen : Window, INotifyPropertyChanged
{
private Dispatcher _dispatcher;
public event PropertyChangedEventHandler PropertyChanged;
private string _progressMessage;
private double _progressValue;
public string ProgressMessage
{
get { return _progressMessage; }
set
{
_progressMessage = value;
OnPropertyChanged("ProgressMessage");
}
}
public double ProgressValue
{
get { return _progressValue; }
set
{
_progressValue = value;
OnPropertyChanged("ProgressValue");
}
}
public ProgressSplashScreen(Action isLoaded)
{
this.Loaded += (sender, args) => isLoaded();
InitializeComponent();
_dispatcher = Dispatcher.CurrentDispatcher;
}
public void SetProgress(double progress, string message)
{
_dispatcher.BeginInvoke(new Action(() =>
{
ProgressValue = progress;
ProgressMessage = message;
}), DispatcherPriority.ContextIdle, null);
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
}
with this as the XAML
<Window x:Class="Application.ProgressSplashScreen"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Splash" BorderBrush="Transparent"
AllowsTransparency="True"
Icon="../../Resources/Icons/Icon.ico"
WindowStartupLocation="CenterScreen"
WindowStyle="None" Width="640" Height="520"
Background="Transparent" Name="SplashWindow" Topmost="True" >
<Grid>
<StackPanel Orientation="Vertical" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch">
<Image Source="../../Resources/Images/splash.jpg" Height="480" Width="640"/>
<Grid>
<ProgressBar Name="SplashProgress" Height="20" Minimum="0" Maximum="100"
BorderBrush="Transparent" Value="{Binding ProgressValue,
UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<Label Name="SplashMessage" VerticalAlignment="Bottom" HorizontalAlignment="Center"
Content="{Binding ProgressMessage,
UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</Grid>
</StackPanel>
</Grid>
</Window>
Any help would be great! Thanks! Really surprised this is as hard as it seems right now...
So what I was talking about is :
MainWindow.xaml
<Window x:Class="SplashSxreenExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Splashscreen"
WindowStyle="none" ResizeMode="NoResize" ShowInTaskbar="False" WindowStartupLocation="CenterScreen"
Height="400" Width="700" Background="#FF292929" FontFamily="Century Gothic"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/SplashScrTemplate.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="AUto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="Test Splash Screen" Foreground="LightGray" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="60"/>
<Label Grid.Row="1" Content="{Binding ProgressMessage}" Foreground="LightGray" FontStyle="Italic"/>
<ProgressBar Grid.Row="2" Height="3" Foreground="White" Style="{StaticResource FlatProgressBar}"
Value="{Binding ProgressValue}"/>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
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 System.ComponentModel;
namespace SplashSxreenExample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _progressMessage;
private int _progressValue;
private BackgroundWorker _mWorker;
public MainWindow()
{
InitializeComponent();
_mWorker = new BackgroundWorker();
_mWorker.WorkerReportsProgress = true; //Allow reporting
_mWorker.ProgressChanged += _mWorker_ProgressChanged;
_mWorker.DoWork += _mWorker_DoWork;
_mWorker.RunWorkerAsync();
}
void _mWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker wkr = sender as BackgroundWorker;
wkr.ReportProgress(0, "Starting..."); //Reporting progress
//Here do your stuff
Thread.Sleep(500);
wkr.ReportProgress(10, "Loading stuff...");
//Here do your stuff
Thread.Sleep(1000);
wkr.ReportProgress(40, "Loading stuff 2...");
//Here do your stuff
Thread.Sleep(500);
wkr.ReportProgress(80, "Loading stuff 3...");
//Here do your stuff
Thread.Sleep(1500);
wkr.ReportProgress(90, "Loading stuff 4...");
//Here do your stuff
Thread.Sleep(2000);
wkr.ReportProgress(100, "Finished");
}
void _mWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ProgressValue = e.ProgressPercentage; //Value
ProgressMessage = e.UserState.ToString(); //Message
}
#region Properties
public string ProgressMessage
{
get { return _progressMessage; }
set
{
_progressMessage = value;
OnPropertyChanged("ProgressMessage");
}
}
public int ProgressValue
{
get { return _progressValue; }
set
{
_progressValue = value;
OnPropertyChanged("ProgressValue");
}
}
#endregion
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
}
And the resource dictionnary (for the flat bar, just in case)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="FlatProgressBar" TargetType="{x:Type ProgressBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ProgressBar">
<Border BorderBrush="{x:Null}" BorderThickness="0" Background="{x:Null}" CornerRadius="0" Padding="0">
<Grid x:Name="PART_Track">
<Rectangle x:Name="PART_Indicator" HorizontalAlignment="Left" Fill="{Binding RelativeSource={RelativeSource AncestorType=ProgressBar},Path=Foreground}" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
This is working pretty well for me, tell me if you have some difficulties.
Here is a ptrscr of the result :
I hope it could help you.
BR,
Bastien.

How do I create a XAML binding to a member variable?

I'm new to XAML and data binding. I want to define a GUI control in MainWindow.xaml that gets its data from a member variable in MainWindow.xaml.cs. For simplicity's sake I just made a program that displays a counter as well as a button to increment the counter.
Based on earlier threads I've looked up, I came up with the following code:
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;
namespace XAMLBindingTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private int Counter
{
get { return (int)GetValue(CounterProperty); }
set { SetValue(CounterProperty, value); }
}
public static readonly DependencyProperty CounterProperty =
DependencyProperty.Register("Counter", typeof(int), typeof(MainWindow), new PropertyMetadata(null));
public MainWindow()
{
Counter = 0;
InitializeComponent();
}
private void incrementCounter(object sender, RoutedEventArgs e)
{
++Counter;
}
}
}
MainWindow.xaml
<Window x:Class="XAMLBindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="140" Width="180">
<Grid>
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBlock x:Name="txbCounter" HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Counter}" VerticalAlignment="Top"/>
<Button x:Name="btnIncrement" Content="Increment" Width="75" Click="incrementCounter"/>
</StackPanel>
</Grid>
</Window>
This example compiles, but the TextBlock isn't showing a counter value. How do I wire the TextBlock to the Counter member in a correct way?
Try adding a "Name" to your window and binding using "ElementName"
<Window x:Class="XAMLBindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Name="UI">
<Grid>
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBlock x:Name="txbCounter" HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding ElementName=UI, Path=Counter}" VerticalAlignment="Top"/>
<Button x:Name="btnIncrement" Content="Increment" Width="75" Click="incrementCounter"/>
</StackPanel>
</Grid>
</Window>
If i understood you correctly:
ItemSource="{Binding Path=TestData, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type common:LayoutAwarePage}}}"
TestData is property of type ObservableCollection declared in .xaml.cs file. ItemSource - is a example property you want bind to.
UPD2:
<ItemsControl ItemSource="{Binding Path=TestData, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type common:LayoutAwarePage}}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Categories

Resources