Wrong order of redo and undo strokes? - c#

I want to implement undo and redo of inkcanvas strokes.
I want to implement redo and undo that can operate multiple times in a row.
I don't know where is the problem with my code.
Please help me.
My code is as follows:
xaml:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<InkCanvas x:Name="inkCanvas"
Grid.Column="0" Grid.ColumnSpan="2"
Grid.Row="0" Grid.RowSpan="7"
Width="Auto" Height="Auto" EditingMode="Ink"
IsHitTestVisible="True"
Background="LightSeaGreen"
UseCustomCursor="True"
Cursor="Pen"/>
<Button x:Name="btn_Test1"
Grid.Row="0"
Grid.Column="1"
Width="100"
Height="50"
Content="pen"
Cursor="Hand"
Tag="Test1"
Click="Button_Click" />
<Button x:Name="btn_Test3"
Grid.Row="1"
Grid.Column="1"
Width="100"
Height="50"
Content="clear"
Tag="Test3"
Click="Button_Click" />
<Button x:Name="btn_Test4"
Grid.Row="2"
Grid.Column="1"
Width="100"
Height="50"
Content="UnDo"
Tag="Undo"
Click="Button_Click" />
<Button x:Name="btn_Test5"
Grid.Row="3"
Grid.Column="1"
Width="100"
Height="50"
Content="ReDo"
Tag="Redo"
Click="Button_Click" />
</Grid>
code behind:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Media;
namespace InkCanvasUndoRedo
{
public partial class MainWindow : Window
{
public Stack<DoStroke> DoStrokes { get; set; }
public Stack<DoStroke> UndoStrokes { get; set; }
private bool handle = true;
public MainWindow()
{
InitializeComponent();
DoStrokes = new Stack<DoStroke>();
UndoStrokes = new Stack<DoStroke>();
inkCanvas.DefaultDrawingAttributes.FitToCurve = true;
inkCanvas.DefaultDrawingAttributes.Color = Color.FromArgb(255, 255, 255, 255);
inkCanvas.Strokes.StrokesChanged += Strokes_StrokesChanged;
}
private void Strokes_StrokesChanged(object sender, StrokeCollectionChangedEventArgs e)
{
if (handle)
{
DoStrokes.Push(new DoStroke
{
ActionFlag = e.Added.Count > 0 ? "ADD" : "REMOVE",
Stroke = e.Added.Count > 0 ? e.Added[0] : e.Removed[0]
});
}
}
public void Undo()
{
handle = false;
if (DoStrokes.Count > 0)
{
DoStroke dos = DoStrokes.Pop();
if (dos.ActionFlag.Equals("ADD"))
{
inkCanvas.Strokes.Remove(dos.Stroke);
}
else
{
inkCanvas.Strokes.Add(dos.Stroke);
}
UndoStrokes.Push(dos);
}
handle = true;
}
public void Redo()
{
handle = false;
if (UndoStrokes.Count > 0)
{
DoStroke dos = UndoStrokes.Pop();
if (dos.ActionFlag.Equals("ADD"))
{
inkCanvas.Strokes.Add(dos.Stroke);
}
else
{
inkCanvas.Strokes.Remove(dos.Stroke);
}
}
handle = true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
switch ((sender as Button).Tag)
{
case "Test1":
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
break;
case "Test3":
inkCanvas.Strokes.Clear();
break;
case "Undo":
Undo();
break;
case "Redo":
Redo();
break;
}
}
}
public struct DoStroke
{
public string ActionFlag { get; set; }
public Stroke Stroke { get; set; }
}
}
The result:
Write: 123
Click: undo->undo->redo->redo->undo
Expected: 3 disappear
Actual: 1 disappears

In your redo Method you do
DoStroke dos = UndoStrokes.Pop();
if (dos.ActionFlag.Equals("ADD"))
{
inkCanvas.Strokes.Add(dos.Stroke);
}
else
{
inkCanvas.Strokes.Remove(dos.Stroke);
}
You should probably call DoStrokes.Push(dos); at the end of this. In a similar way as is done in the Undo-method.

Related

How to update data in a new non-modal window after changing the selection to ListView?

I have a user list in MainWindow. After pressing the preview button, a non-modal window for data editing opens. Updated data are changed in real time in the main window. The question is how to bind the windows so that because the user changes from the list in the main window, he changes in real time in an already open non-modal window.
WPF does not recommend coding business logic directly in xaml.cs
files.
It is recommended that you write code using the MVVM pattern
ViewModel
public class podgladUzytkownika : INotifyPropertyChanged
{
private string imie;
private string nazwisko;
private string mail;
public string Mail
{
get => mail;
set => this.SetValue(ref mail, value);
}
public string Nazwisko
{
get => nazwisko;
set => this.SetValue(ref nazwisko, value);
}
public string Imie
{
get => imie;
set => this.SetValue(ref imie, value);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void SetValue<T>(ref T oldValue, T newValue, [CallerMemberName] string propertyName = null)
{
oldValue = newValue;
OnPropertyChanged(propertyName);
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MainWindowViewModel
{
private int refreshCount;
public ICommand RefreshCommand { get; }
public ICommand PodgladUzytkownikaShow { get; }
public podgladUzytkownika data { get; }
public MainWindowViewModel()
{
data = new podgladUzytkownika();
PodgladUzytkownikaShow = new Command(PodgladUzytkownikaShowExecute);
RefreshCommand = new Command(RefreshCommandExecute);
}
private void PodgladUzytkownikaShowExecute(object obj)
{
var window = new Window();
window.DataContext = data;
window.Show();
}
private void RefreshCommandExecute(object obj)
{
// Data updates are passed to the view
refreshCount++;
data.Imie = nameof(data.Imie) + refreshCount;
data.Nazwisko = nameof(data.Nazwisko) + refreshCount;
data.Mail = nameof(data.Mail) + refreshCount;
}
}
View
// MainWindow.xaml
<StackPanel x:Name="StackPanel1">
<Button Content="PodgladUzytkownika" Command="{Binding Path=PodgladUzytkownikaShow}"/>
<Button Content="Refresh" Command="{Binding Path=RefreshCommand}"/>
</StackPanel>
// window.xaml
<StackPanel >
<TextBlock Text="{Binding Path=Imie }"/>
<TextBlock Text="{Binding Path=Nazwisko }"/>
<TextBlock Text="{Binding Path=Mail }"/>
</StackPanel>
Demo
this.MainWindow.DataContext =new MainWindowViewModel();
After chasing one problem after another with your comments, the problem is your code is not well-designed. Using data bindings (one of the prime benefits of WPF), you can stop chasing your tail with trying to figure out how to update one UI when data changes. Here is a simplified version of your code that will always ensure the UI matches the data you wish to manipulate.
MainWindow.xaml
<Grid Margin="3">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Label Margin="3" Grid.ColumnSpan="3">Lista użytkowników</Label>
<Button Margin="3" Padding="3" Grid.Row="2" Grid.ColumnSpan="3" Click="Zamknij_Click">Zamknij</Button>
<StackPanel Margin="3" Grid.Column="2" Grid.Row="1">
<!--<Button Name="Dodaj" Click="Dodaj_Click" Margin="3" Padding="10,3" >Dodaj...</Button>-->
<!--<Button Name="Usun" IsEnabled="False" Click="Usun_Click" Margin="3" Padding="10,3" >Usuń</Button>-->
<!--<Button Name="Edytuj" IsEnabled="False" Click="Edytuj_Click" Margin="3" Padding="10,3" >Edytuj...</Button>-->
<Button Name="Podglad" IsEnabled="False" Click="Podglad_Click" Margin="3" Padding="10,3" >Podgląd...</Button>
</StackPanel>
<ListView SelectionMode="Single" SelectionChanged="Selection_Changed" Name="lv_uzytkownicy" Margin="3" Grid.Row="1">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Imię"
DisplayMemberBinding="{Binding Imie}"/>
<GridViewColumn Header="Nazwisko"
DisplayMemberBinding="{Binding Nazwisko}" />
<GridViewColumn Header="Mail"
DisplayMemberBinding="{Binding Mail}"/>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
<GridSplitter Grid.Column="1" Grid.Row="1" Width="5" ResizeDirection="Columns" HorizontalAlignment="Center"/>
</Grid>
MainWindow.xaml.cs
using System.Collections.ObjectModel;
public partial class MainWindow : Window
{
public ObservableCollection<Uzytkownik> listaUzytkownikow = new ObservableCollection<Uzytkownik>();
Podglad_Uzytkownika podgladUzytkownika;
public MainWindow()
{
InitializeComponent();
lv_uzytkownicy.ItemsSource = listaUzytkownikow;
listaUzytkownikow.Add(new Uzytkownik("Mietek", "Żul", "sikalafa#wp.pl"));
listaUzytkownikow.Add(new Uzytkownik("Franek", "Alpinista", "halo#gmail.pl"));
listaUzytkownikow.Add(new Uzytkownik("Stefan", "Ulążka", "mam.to#o2.pl"));
this.DataContext = this;
}
private void Podglad_Click(object sender, RoutedEventArgs e)
{
podgladUzytkownika = new Podglad_Uzytkownika();
podgladUzytkownika.DataContext = lv_uzytkownicy.SelectedItem;
podgladUzytkownika.Show();
}
private void Zamknij_Click(object sender, RoutedEventArgs e)
{
Close();
}
private void Selection_Changed(object sender, SelectionChangedEventArgs e)
{
if (lv_uzytkownicy.SelectedItems.Count > 0) Podglad.IsEnabled = true;
else Podglad.IsEnabled = false;
if (podgladUzytkownika != null && podgladUzytkownika.IsVisible)
{
podgladUzytkownika.DataContext = lv_uzytkownicy.SelectedItem;
}
}
}
Podglad_Uzytkownika.xaml
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Margin="3">Imię</Label>
<Label Margin="3" Grid.Row="1">Nazwisko</Label>
<Label Margin="3" Grid.Row="2">Email</Label>
<TextBox Name="imieTextBox" Text="{Binding Imie, UpdateSourceTrigger=PropertyChanged}" Margin="3" Grid.Column="1"/>
<TextBox Name="nazwiskoTextBox" Text="{Binding Nazwisko, UpdateSourceTrigger=PropertyChanged}" Margin="3" Grid.Column="1" Grid.Row="1"/>
<TextBox Name="mailTextBox" Text="{Binding Mail, UpdateSourceTrigger=PropertyChanged}" Margin="3" Grid.Column="1" Grid.Row="2"/>
<Grid HorizontalAlignment="Center" Grid.ColumnSpan="2" Grid.Row="3" Grid.IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="pierwsza" />
</Grid.ColumnDefinitions>
<Button Margin="3" Padding="20, 5" Name="Podglad" Click="Podglad_Click" IsDefault="True">Zamknij</Button>
</Grid>
</Grid>
Podglad_Uzytkownika.xaml.cs
public partial class Podglad_Uzytkownika : Window
{
public Podglad_Uzytkownika()
{
InitializeComponent();
}
private void Podglad_Click(object sender, RoutedEventArgs e)
{
Close();
}
}
Uzytkownik.cs
public class Uzytkownik : INotifyPropertyChanged
{
private string imie;
private string nazwisko;
private string mail;
public Uzytkownik(string imie, string nazwisko, string mail)
{
this.Imie = imie;
this.Nazwisko = nazwisko;
this.Mail = mail;
}
public string Imie { get => this.imie; set { this.imie = value; OnPropertyChanged(); } }
public string Nazwisko { get => this.nazwisko; set { this.nazwisko = value; OnPropertyChanged(); } }
public string Mail { get => this.mail; set { this.mail = value; OnPropertyChanged(); } }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

CollectionView, DataBinding, MVVM

Hi everyone,
I am trying to implement MVVM in my application but i am failing to load data.
I have a main page and it works fine, but once I want to navigate to the detail of my Ad and then the detail page is blank. There are my controls so i know that the pages is loaded just my data are missing. I cant seem to figure out where i have made the mistake. I am new to coding so i sometimes tend to make very silly mistakes. I been trying to solve this for past few hours otherwise would not post it over here. Thank you of any opinion.
My HomePage
<Grid Grid.Row="1" Margin="0,25,0,0">
<CollectionView x:Name="ads"
ItemsSource="{Binding AdLogEntries}"
ItemTemplate="{StaticResource HomePageTemplate}"
SelectionMode="Single"
SelectedItem="{Binding SelectedAd, Mode=TwoWay}"
SelectionChanged="CollectionView_SelectionChanged"
Margin="12,0">
</CollectionView>
</Grid>
public partial class HomePage : ContentPage
{
public HomePage()
{
InitializeComponent();
BindingContext = new HomePage ViewModel();
}
async void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedAd = (AdLogEntry)e.CurrentSelection.FirstOrDefault();
if (selectedAd != null)
{
await Navigation.PushAsync(new AdDetail(selectedAd));
}
}
}
namespace Baltazar.ViewModel
{
public class HomePageViewModel : BaseViewModel
{
ObservableCollection<AdLogEntry> _adLogEntries;
public ObservableCollection<AdLogEntry> AdLogEntries { get => _adLogEntries; set { _adLogEntries = value; OnPropertyChanged(); } }
public AdLogEntry selectedAd;
public HomePageViewModel()
{
AdLogEntries = new ObservableCollection<AdLogEntry>()
{
new AdLogEntry (){Id = 0, Image = "cat.jpg", Name = "Kocka" , Description = "seda kocka na prodej, mayliva, hrava, spolecenska " ,Price = 120, },
new AdLogEntry (){Id = 1, Image = "cat2.jpg", Name = "Kocka", Description = "seda kocka na prodej, mayliva, hrava, spolecenska " ,Price = 120, },
new AdLogEntry (){Id = 2, Image = "bobtailjpg.jpg", Name = "Kocka",Description = "seda kocka na prodej, mayliva, hrava, spolecenska ", Price = 120, },
};
}
}
}
//Detail
public class AdDetailViewModel : BaseViewModel
{
AdLogEntry _adDetail;
public AdLogEntry AdDetail { get => _adDetail;set { _adDetail = value;OnPropertyChanged(); } }
public AdDetailViewModel(AdLogEntry adDetail)
{
AdDetail = adDetail;
}
}
public partial class AdDetail : ContentPage
{
//private AdLogEntry selectedAd;
public AdDetail(AdLogEntry adDetail)
{
InitializeComponent();
BindingContext = new AdDetailViewModel(adDetail);
}
}
//BaseViewModel
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected BaseViewModel()
{
}
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="300" />
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ffimageloading:CachedImage
x:Name="HeaderView"
Grid.Row="0"
Grid.RowSpan="2"
Aspect="AspectFill"
Source="{Binding AdLogEntries.Image}"/>
<controls:Parallax Control
x:Name="Parallax"
Grid.Row="0"
Grid.RowSpan="3">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="300" />
<RowDefinition />
</Grid.RowDefinitions>
<yummy:Pancake View
Grid.Row="1"
CornerRadius="24, 24, 0, 0"
BackgroundColor="{StaticResource BackgroundColor}"
Margin="0, 20, 0, 0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Animal NAME -->
<Label
Grid.Row="0"
Text="{Binding AdLogEntries.Name}"
/>
<!-- QUANTITY -->
<Grid
Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label
Grid.Column="1"
Text="{Binding AdLogEntries.Price, StringFormat='{0:C0}'}"
/>
</Grid>
<!-- ABOUT -->
<Label
Grid.Row="2"
Text="Popis"
/>
<!-- DESCRIPTION -->
<Label
Grid.Row="3"
Text="{Binding AdLogEntries.Description}"
/>
<Grid
Grid.Row="4"
Margin="0, 12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- BUY NOW BUTTON -->
<yummy:PancakeView
Grid.Column="1"
HeightRequest="48"
CornerRadius="24, 0, 24, 0"
Background Color="Accent"
Margin="24, 0, 0, 0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label
Grid.Column="1"
Text="Buy now"
/>
<Label
Grid.Column="2"
Text=">"
/>
</Grid>
</yummy:Pancake View>
</Grid>
</Grid>
</yummy:Pancake View>
</Grid>
</controls:Parallax Control>
</Grid>
</ContentPage.Content>
Your SelectedItem never changes because you are not trigger OnPropertyChange. You can change your view model logic like this:
private AdLogEntry selectedAd;
public AdLogEntry SelectedAd { get => selectedAd; set { selectedAd = value; OnPropertyChanged("SelectedAd"); } }
public ICommand AdSelectionChangedCommand => new Command(AdSelectionChanged);
private void AdSelectionChanged()
{
OnPropertyChanged("SelectedAd");
Application.Current.MainPage.Navigation.PushModalAsync(new DetailPage(SelectedAd));
}
And in your XAML:
<CollectionView x:Name="ads"
ItemsSource="{Binding AdLogEntries}"
SelectionMode="Single"
SelectionChangedCommand="{Binding AdSelectionChangedCommand}"
SelectedItem="{Binding SelectedAd, Mode=TwoWay}"
Margin="12,0">
Your detail page:
public DetailPage(AdLogEntry detail)
{
this.BindingContext = new AdDetailViewModel(adDetail);
InitializeComponent();
}
In Detail XAML:
<Label Text="{Binding AdDetail.Name}"/>
your BindingContext is AdDetailViewModel
BindingContext = new AdDetailViewModel(adDetail);
and your binding paths are like
<Label Grid.Row="3" Text="{Binding AdLogEntries.Description}"
AdDetailViewModel does not have a AdLogEntries property. It does have a AdDetail, so presumably you should use this as a binding path
<Label Grid.Row="3" Text="{Binding AdDetail.Description}"
The problem is in your detail page XAML. To be precise, the problem is in your XAML Binding Expressions. All the bindings in the detail page has wrong path set. For example, for image control it should be Source="{Binding AdDetail.Image}" instead of Source="{Binding AdLogEntries.Image}". It happens all the time and you catch these kind of errors in the output log when you debug the application.

WPF Binding a label with properties

On my WPF app page i have 2 bindings
1. for a list of items as an observable collection
2. just to show some values on a lable using binding
My class struct like this
public DbVersionModel DbVersion { get; set; }
public ObservableCollection<BookStore> StoreCollection
{ get { return thisApp.app_Stores; } }
public class DbVersionModel : INotifyPropertyChanged
{
private int _LocalVersion { get; set; }
private int _ServerVersion { get; set; }
private int _ActiveStores { get; set; }
private string _LastModifiedLocal { get; set; }
private string _LastModifiedServer { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyChange(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
public int LocalVersion
{
get { return _LocalVersion; }
set
{
_LocalVersion = value;
NotifyChange(new PropertyChangedEventArgs("LocalVersion"));
}
}
public int ServerVersion
{
get { return _ServerVersion; }
set
{
_ServerVersion = value;
NotifyChange(new PropertyChangedEventArgs("ServerVersion"));
}
}
public int ActiveStores
{
get { return _ActiveStores; }
set
{
_ActiveStores = value;
NotifyChange(new PropertyChangedEventArgs("ActiveStores"));
}
}
public string LastModifiedLocal
{
get { return _LastModifiedLocal; }
set
{
_LastModifiedLocal = value;
NotifyChange(new PropertyChangedEventArgs("LastModifiedLocal"));
}
}
public string LastModifiedServer
{
get { return _LastModifiedServer; }
set
{
_LastModifiedServer = value;
NotifyChange(new PropertyChangedEventArgs("LastModifiedServer"));
}
}
} public ManagePage()
{
InitializeComponent();
setContext();
}
private void setContext()
{
try
{
DbVersionModel db_version = new DbVersionModel();
db_version.LastModifiedServer = //set with value;
db_version.ServerVersion = //set with value;
db_version.LocalVersion = //set with value;
db_version.LastModifiedLocal = //set with value;
db_version.ActiveStores = //set with value;
this.DbVersion = db_version;
}
catch
{
}
}
xaml like this
<Page x:Class="App.ManagePage"
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"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
mc:Ignorable="d">
<Page.Resources>
</Page.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" >
<Grid Margin="5 10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"></ColumnDefinition>
<ColumnDefinition ></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<!--// -->
<Label Content="Active stores[Local]" Grid.Column="0" Grid.Row="0" ></Label>
<Label Content="{Binding Source=DbVersion, Path=ActiveStores}" Grid.Column="1" Grid.Row="0" ></Label>
<Label Content="Current version [Local]" Grid.Column="0" Grid.Row="1" ></Label>
<Label Content="{Binding Source=DbVersion, Path=LocalVersion}" Grid.Column="1" Grid.Row="1" ></Label>
<Label Content="Curretn Version [Server]" Grid.Column="0" Grid.Row="2" ></Label>
<Label Content="{Binding Source=DbVersion, Path=ServerVersion}" Grid.Column="1" Grid.Row="2" ></Label>
<Label Content="Last modified [Local]" Grid.Column="0" Grid.Row="3" ></Label>
<Label Content="{Binding Source=DbVersion, Path=LastModifiedLocal}" Grid.Column="1" Grid.Row="3" ></Label>
<Label Content="Last modified [Server]" Grid.Column="0" Grid.Row="4" ></Label>
<Label Content="{Binding Source=DbVersion, Path=LastModifiedServer}" Grid.Column="1" Grid.Row="4" ></Label>
<StackPanel Grid.Column="0" Grid.ColumnSpan="5" Grid.Row="6" HorizontalAlignment="Center">
<Button Name="btnSync" Content="Sync stores" Height="30" Click="btnSync_Click" Style="{StaticResource ActionButtons}"></Button>
</StackPanel>
</Grid>
</ScrollViewer>
Also have a ItemsControl which is getting loaded like this and binding is working fine here
<ItemsControl Name="StoreListView" ItemsSource="{Binding StoreCollection}" Margin="5" VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling" >
But ObservableCollection list binding is fine , but the label bindings are not working. How i can solve this?
How can i set binding on label based on properties of a class
I think WPF does not notice the change of the DbVersion property because you set it after calling InitializeComponent(). Either you implement it as a DependencyProperty, which automatically notices if it is changed (see: https://msdn.microsoft.com/en-us/library/ms750428(v=vs.110).aspx), or you use the INotifyPropertyChanged interface in your ManagePage class (see: https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx).

Crash and bluescreen (ntoskrnl.exe) when pinging servers from c# wpf

I was writing a little tool for work to check ping latency to our servers in c# wpf. I've done a similar thing with Windows Forms and the occuring problem appears to be the same. After some time i get a bluescreen including memory dump. The problem was caused by ntoskrnl.exe and I have no idea why. All I do is ping some servers every 1000 ms.
Here's my c# code:
using MahApps.Metro.Controls;
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 System.Collections.ObjectModel;
using System.Windows.Threading;
using System.Net.NetworkInformation;
using System.ComponentModel;
namespace NetworkChecker
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : MetroWindow
{
ObservableCollection<PingTarget> PingTargets = new ObservableCollection<PingTarget>();
PingTargetHost pth = new PingTargetHost();
public MainWindow()
{
pth.PingTargetList = new ObservableCollection<PingTarget>();
InitializeComponent();
PingTarget ptExample = new PingTarget { TargetName = "Google", TargetIP = "www.google.ch" };
pth.PingTargetList.Add(ptExample);
PingTargetListBox.ItemsSource = pth.PingTargetList;
}
private void AddNewTarget_Click(object sender, RoutedEventArgs e)
{
PingTarget newTarget = new PingTarget { TargetName = NewTargetNametb.Text, TargetIP = NewTargetIPtb.Text };
pth.PingTargetList.Add(newTarget);
}
}
public class PingTarget : INotifyPropertyChanged
{
public PingTarget()
{
PingCollection = new ObservableCollection<KeyValuePair<DateTime, long>>();
this.Active = true;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
private string _TargetName;
public string TargetName
{
get { return _TargetName; }
set { _TargetName = value; OnPropertyChanged("TargetName"); }
}
private string _TargetIP;
public string TargetIP
{
get { return _TargetIP; }
set { _TargetIP = value; OnPropertyChanged("TargetIP"); }
}
private ObservableCollection<KeyValuePair<DateTime, long>> _PingCollection;
public ObservableCollection<KeyValuePair<DateTime, long>> PingCollection
{
get { return _PingCollection; }
set { _PingCollection = value; OnPropertyChanged("PingCollection"); }
}
public long MaxPing
{
get
{
return PingCollection.Max(p => p.Value);
}
}
public long MinPing
{
get
{
return PingCollection.Min(p => p.Value);
}
}
public long AvgPing
{
get
{
return (long)PingCollection.Average(p => p.Value);
}
}
private bool _Active;
public bool Active
{
get { return _Active; }
set { _Active = value; OnPropertyChanged("Active"); }
}
}
public class PingTargetHost : INotifyPropertyChanged
{
public PingTargetHost(int PingInterval = 1000)
{
PingFrequency = PingInterval;
Ticker = new DispatcherTimer();
Ticker.Interval = new TimeSpan(0, 0, 0, 0, PingFrequency);
Ticker.Tick += Ticker_Tick;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
void Ticker_Tick(object sender, EventArgs e)
{
foreach (PingTarget pt in PingTargetList.Where(pts => pts.Active == true))
{
Ping pingSender = new Ping();
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
int timeout = 10000;
byte[] buffer = Encoding.ASCII.GetBytes(data);
PingReply Result = pingSender.Send(pt.TargetIP, timeout, buffer);
string Pong = Result.RoundtripTime.ToString();
if (Result.Status == IPStatus.Success)
{
KeyValuePair<DateTime, long> ping = new KeyValuePair<DateTime, long>(DateTime.Now, Result.RoundtripTime);
pt.PingCollection.Add(ping);
}
if (Result.Status == IPStatus.TimedOut)
{
}
}
}
public void StopTicker()
{
Ticker.Stop();
}
public void StartTicker()
{
Ticker.Start();
}
private DispatcherTimer Ticker { get; set; }
public int PingFrequency { get; set; }
public ObservableCollection<PingTarget> PingTargetList { get; set; }
}
}
Here's my WPF code:
<Controls:MetroWindow x:Class="NetworkChecker.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
Title="Simple Network Checker" Height="600" Width="1000">
<Grid x:Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="5" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Column="1" >
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
</StackPanel>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="5" />
<RowDefinition Height="150" />
</Grid.RowDefinitions>
<ListBox x:Name="PingTargetListBox" DataContext="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Label Content="{Binding TargetName}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Separator Margin="2" Grid.Row="1" />
<Grid Grid.Row="2">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBox x:Name="NewTargetIPtb" Controls:TextBoxHelper.Watermark="Target IP" Controls:TextBoxHelper.UseFloatingWatermark="True" />
<TextBox x:Name="NewTargetNametb" Grid.Row="1" Controls:TextBoxHelper.Watermark="Target Name" Controls:TextBoxHelper.UseFloatingWatermark="True" />
<Button x:Name="AddNewTarget" Click="AddNewTarget_Click" Content="Hinzufügen" Grid.Row="2" />
</Grid>
</Grid>
<Grid Grid.Column="2" DataContext="{Binding ElementName=PingTargetListBox, Path=SelectedItem}">
<Grid.RowDefinitions >
<RowDefinition />
<RowDefinition Height="5" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox x:Name="DetailsPingListBox" ItemsSource="{Binding PingCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Label Content="{Binding Key}" />
<Label Content="{Binding Value}" Grid.Column="1" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Separator Grid.Row="1" Margin="2" />
<StackPanel Grid.Row="2">
<CheckBox x:Name="ActiveInactive" IsChecked="{Binding Active}" Content="Aktiv" />
<TextBlock>
Maximum: <TextBlock Text="{Binding MaxPing}" />
</TextBlock>
<TextBlock>
Minimum: <TextBlock Text="{Binding MinPing}" />
</TextBlock>
<TextBlock>
Average: <TextBlock Text="{Binding AvgPing}" />
</TextBlock>
</StackPanel>
</Grid>
</Grid>
Any ideas?
I'd really love this tool to work without bluescreens ;)
Thanks a lot for your help!
Mo

Draw 4 quadrants in a Button and change each one's background with binding

How can I go about splitting a WPF Button into 4 quadrants and customize it so that I can set Background Color binding for each quadrant separately with Binding Path to separate properties.
It is nice if Button also has property to control whether each quadrant is clickable or only one click event is raised as a whole for each quadrant.
Assuming that if you are talking about binding, then you are using MVVM pattern
In the View-XAML create a button and add 4 rectangles within the content of the button.
<Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="150" Height="150" Command="{Binding RectangleButtonClick}">
<Button.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75"/>
<RowDefinition Height="75"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="75"/>
</Grid.ColumnDefinitions>
<Rectangle x:Name="SecondQuad" Grid.Row="0" Grid.Column="0" Fill="{Binding SecondQuadColor}" />
<Rectangle x:Name="FirstQuad" Grid.Row="0" Grid.Column="1" Fill="{Binding FirstQuadColor}"/>
<Rectangle x:Name="ThirdQuad" Grid.Row="1" Grid.Column="0" Fill="{Binding ThirdQuadColor}"/>
<Rectangle x:Name="FourthQuad" Grid.Row="1" Grid.Column="1" Fill="{Binding FourthQuadColor}"/>
</Grid>
</Button.Content>
</Button>
In your ViewModel
public class MyViewModel
{
private SolidColorBrush _FirstQuadColor;
public SolidColorBrush FirstQuadColor
{
get { return _FirstQuadColor; }
set { _FirstQuadColor = value; OnPropertyChanged("FirstQuadColor"); }
}
private SolidColorBrush _SecondQuadColor;
public SolidColorBrush SecondQuadColor
{
get { return _SecondQuadColor; }
set { _SecondQuadColor = value; OnPropertyChanged("SecondQuadColor"); }
}
private SolidColorBrush _ThirdQuadColor;
public SolidColorBrush ThirdQuadColor
{
get { return _ThirdQuadColor; }
set { _ThirdQuadColor = value; OnPropertyChanged("ThirdQuadColor"); }
}
private SolidColorBrush _FourthQuadColor;
public SolidColorBrush FourthQuadColor
{
get { return _FourthQuadColor; }
set { _FourthQuadColor = value; OnPropertyChanged("FourthQuadColor"); }
}
private ICommand _RectangleButtonClick;
public ICommand RectangleButtonClick
{
get { return _RectangleButtonClick; }
set { _RectangleButtonClick = value; OnPropertyChanged("RectangleButtonClick"); }
}
public MyViewModel()
{
RectangleButtonClick = new DelegateCommand(RectangleButtonClick_Execute);
FirstQuadColor = Brushes.Red;
SecondQuadColor = Brushes.Green;
ThirdQuadColor = Brushes.Blue;
FourthQuadColor = Brushes.Yellow;
}
void RectangleButtonClick_Execute()
{
var directlyOver = Mouse.DirectlyOver;
if (directlyOver is Rectangle)
{
var selectedRectangle = (directlyOver as Rectangle);
switch (selectedRectangle.Name)
{
case "FirstQuad" : Console.Write("First Quad clicked"); break;
case "SecondQuad": Console.Write("Second Quad clicked"); break;
case "ThirdQuad": Console.Write("Third Quad clicked"); break;
case "FourthQuad": Console.Write("Fourth Quad clicked"); break;
}
}
}
}
There are actually lots of different ways to do this, the best method will depend on the specifics of your implementation. I'll provide one method here but be advised it's by no means the best (particularly if you're doing MVVM, which you should be).
<Button x:Name="MyButton" Margin="93,92,68,77" >
<Button.Template>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100*" />
<ColumnDefinition Width="100*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100*" />
<RowDefinition Height="100*" />
</Grid.RowDefinitions>
<Rectangle Grid.Column="0" Grid.Row="0" Fill="{Binding Brush00}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseDown="UserControl_MouseDown_1"/>
<Rectangle Grid.Column="0" Grid.Row="1" Fill="{Binding Brush01}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseDown="UserControl_MouseDown_2"/>
<Rectangle Grid.Column="1" Grid.Row="0" Fill="{Binding Brush10}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseDown="UserControl_MouseDown_3"/>
<Rectangle Grid.Column="1" Grid.Row="1" Fill="{Binding Brush11}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseDown="UserControl_MouseDown_4" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
And then in the code behind:
public partial class MyParentWindow : Window
{
public MyParentWindow()
{
InitializeComponent();
this.MyButton.DataContext = new ButtonModel();
}
private void UserControl_MouseDown_1(object sender, RoutedEventArgs e)
{
}
private void UserControl_MouseDown_2(object sender, RoutedEventArgs e)
{
}
private void UserControl_MouseDown_3(object sender, RoutedEventArgs e)
{
}
private void UserControl_MouseDown_4(object sender, RoutedEventArgs e)
{
}
}
public class ButtonModel
{
public Brush Brush00 { get { return Brushes.Red; } }
public Brush Brush01 { get { return Brushes.Green; } }
public Brush Brush10 { get { return Brushes.Blue; } }
public Brush Brush11 { get { return Brushes.Yellow; } }
}

Categories

Resources