I have a UserControl which contains a InkToolbar. In this control I'm generating another set of UserControls based on user input. In each of those programmatically generated controls, contains a InkCanvas.
This is the parent UserControl & the code behind.
Main.xaml
<UserControl
x:Class="uwp.Main"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:uwp_mvvm"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0">
<InkToolbar x:Name="InkToolbar" Background="Black" Margin="10 0 0 0" VerticalAlignment="Center"/>
</StackPanel>
<ScrollViewer ZoomMode="Enabled" Background="DarkGray" x:Name="ScrollViewer" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" MinZoomFactor="0.25" Width="Auto" Height="Auto" MaxZoomFactor="4" Grid.Row="1">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
<ItemsControl x:Name="PagesItemsControl" ItemsSource="{x:Bind Pages, Mode=OneWay}" HorizontalAlignment="Center" VerticalAlignment="Top">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:TestControl x:Name="TestControl" Page="{Binding}" Margin="4 4" InkToolbarControl="{Binding Path=InkToolbar, ElementName=InkToolbar}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</Grid>
</UserControl>
Main.xaml.cs
public sealed partial class MainViewer : UserControl
{
public MainViewer()
{
this.InitializeComponent();
}
private void EventTriggerChanged(object sender, PropertyChangedEventArgs e)
{
var trigger = sender as EventTriggerTestControl;
if (trigger != null)
RaiseChanged(e.PropertyName);
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
private PdfDocument pdfDocument = null;
private string password = string.Empty;
private ObservableCollection<PdfPage> pages = new ObservableCollection<PdfPage>();
public string Password
{
private get { return password; }
set { if (value != password) { password = value; } }
}
public ObservableCollection<PdfPage> Pages
{
get { return pages; }
set { if (value != pages) { pages = value; } }
}
public StorageFile File
{
get { return (StorageFile)GetValue(FileProperty); }
set { SetValue(FileProperty, value); }
}
public static readonly DependencyProperty FileProperty =
DependencyProperty.Register(nameof(File), typeof(StorageFile), typeof(MainViewer), new PropertyMetadata(null, new PropertyChangedCallback(OnDocumentChanged)));
private static void OnDocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (object.Equals(e.NewValue, e.OldValue) || e.NewValue is null)
return;
d.RegisterPropertyChangedCallback(FileProperty, CaptureDocument);
}
private async static void CaptureDocument(DependencyObject sender, DependencyProperty dp) => await (sender as MainViewer).OpenFileAsync(sender.GetValue(dp) as StorageFile);
private async Task OpenFileAsync(StorageFile file)
{
try
{
if (file == null)
throw new ArgumentNullException(nameof(file));
var files = await ApplicationData.Current.LocalFolder.GetFilesAsync(CommonFileQuery.OrderByName);
if (files.Where(x => x.Name == file.Name).ToList().Count == 0)
await file.CopyAsync(ApplicationData.Current.LocalFolder, file.Name, NameCollisionOption.ReplaceExisting);
file = await ApplicationData.Current.LocalFolder.GetFileAsync(file.Name);
pdfDocument = new PdfDocument(file.Path, Password);
pdfDocument.Pages.ToList().ForEach(x => Pages.Add(x));
}
catch (Exception ex) { throw ex; }
}
}
I want to use the InkToolbar which is in the parent control inside the TestControl
TestControl.xaml
<UserControl
x:Class="uwp.TestControl"
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="using:uwp_mvvm.ViewModels" xmlns:converter="using:uwp_mvvm"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<UserControl.Resources>
<converter:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
</UserControl.Resources>
<Grid x:Name="Viewport" VerticalAlignment="Top" HorizontalAlignment="Center">
<Border x:Name="ViewportBorder" Background="White" BorderThickness="2, 2, 2, 2" BorderBrush="#FF353334" />
<Image x:Name="Image" Margin="0" UseLayoutRounding="True" ManipulationMode="Scale"/>
<Canvas x:Name="SelectionCanvas" CompositeMode="MinBlend" Opacity="1" />
<InkCanvas x:Name="InkCanvas" />
</Grid>
</UserControl>
TastControl.xaml.cs
public sealed partial class TestControl : UserControl
{
private const float DPI = 256;
public PdfPage Page
{
get { return (PdfPage)GetValue(PageProperty); }
set { SetValue(PageProperty, value); }
}
public static readonly DependencyProperty PageProperty =
DependencyProperty.Register(nameof(Page), typeof(PdfPage), typeof(TestControl), new PropertyMetadata(null, new PropertyChangedCallback(OnPageChanged)));
private static void OnPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (object.Equals(e.NewValue, e.OldValue) || e.NewValue is null)
return;
d.RegisterPropertyChangedCallback(PageProperty, CapturePage);
}
private static void CapturePage(DependencyObject sender, DependencyProperty dp) => (sender as TestControl).RenderPage(sender.GetValue(dp) as PdfPage);
public InkToolbar InkToolbarControl
{
get { return (InkToolbar)GetValue(InkToolbarControlProperty); }
set { SetValue(InkToolbarControlProperty, value); }
}
public static readonly DependencyProperty InkToolbarControlProperty =
DependencyProperty.Register(nameof(InkToolbarControl), typeof(InkToolbar), typeof(TestControl), new PropertyMetadata(null));
public TestControl()
{
this.InitializeComponent();
ConfigureInkCanvas();
}
private void ConfigureInkCanvas()
{
InkCanvas.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Pen | CoreInputDeviceTypes.Touch;
InkCanvas.InkPresenter.InputProcessingConfiguration.Mode = InkInputProcessingMode.None;
InkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(
new InkDrawingAttributes
{
IgnorePressure = false,
FitToCurve = true,
Color = Colors.Black,
PenTip = PenTipShape.Circle
});
InkCanvas.InkPresenter.UnprocessedInput.PointerEntered -= InkCanvasUnprocessedInputPointerEntered;
InkCanvas.InkPresenter.UnprocessedInput.PointerEntered += InkCanvasUnprocessedInputPointerEntered;
InkCanvas.InkPresenter.UnprocessedInput.PointerExited -= InkCanvasUnprocessedInputPointerExited;
InkCanvas.InkPresenter.UnprocessedInput.PointerExited += InkCanvasUnprocessedInputPointerExited;
}
private void InkCanvasUnprocessedInputPointerExited(InkUnprocessedInput sender, PointerEventArgs args)
{
//InkCanvas.InkPresenter.InputProcessingConfiguration.Mode = InkInputProcessingMode.Inking;
//InkToolbarControl.TargetInkCanvas = InkCanvas;
}
private void InkCanvasUnprocessedInputPointerEntered(InkUnprocessedInput sender, PointerEventArgs args)
{
//InkCanvas.InkPresenter.InputProcessingConfiguration.Mode = InkInputProcessingMode.None;
//InkToolbarControl.TargetInkCanvas = null;
}
private void RenderPage(PdfPage page, float dpi = DPI)
{
if (page is null)
return;
this.DataContext = page;
var width = (DataContext as PdfPage).Width;
var height = (DataContext as PdfPage).Height;
var writableBitmap = new WriteableBitmap((int)(width / 72f * dpi), (int)(height / 72f * dpi));
(DataContext as PdfPage).Render(writableBitmap, PageOrientations.Normal, RenderingFlags.Annotations);
Image.Width = width;
Image.Height = height;
Image.Source = writableBitmap;
SelectionCanvas.Width = width;
SelectionCanvas.Height = height;
InkCanvas.Width = width;
InkCanvas.Height = height;
Canvas.SetZIndex(Image, 0);
ConfigureInkCanvas();
}
}
I tried to use a DependencyProperty to send the InkToolbar to the TestControl but it didn't seem to work.
Could someone please help me with this? I'm not sure whether it is possible to set the TargetInkCanvas like this also. So, if there is a better approach for this any suggestions are also appreciated.
Any help is much appreciated. Thanks.
Access InkToolbar placed in parent element from programmatically generated child elements
Above solution that use DependencyProperty to pass parent InkToolBar is correct. However you bind wrong value for InkToolbarControl property.
Please bind ElementName without path directly.
<local:TestControl
x:Name="TestControl"
Margin="4,4"
InkToolbarControl="{Binding ElementName=InkToolbar}" />
Then update InkCanvasUnprocessedInputPointerExited and InkCanvasUnprocessedInputPointerEntered process logic.
private void InkCanvasUnprocessedInputPointerExited(InkUnprocessedInput sender, PointerEventArgs args)
{
InkCanvas.InkPresenter.InputProcessingConfiguration.Mode = InkInputProcessingMode.Inking;
InkToolbarControl.TargetInkCanvas = null;
}
private void InkCanvasUnprocessedInputPointerEntered(InkUnprocessedInput sender, PointerEventArgs args)
{
InkCanvas.InkPresenter.InputProcessingConfiguration.Mode = InkInputProcessingMode.None;
InkToolbarControl.TargetInkCanvas = InkCanvas;
}
Related
I am looking for a wrappanel or rather something that works similarly. The wrappanel grabs the Uielement in a new line, but the elements are not dynamic in width, but static. The setting »HorizontalAlignment=" Stretch"« does not work and the elements look squeezed together. That means you have to put the width manually »Width="200"« and that is very static. So when I change the width of my window, more elements come into one line, but the existing elements do not adapt to the width of the window. I would have liked to fill out the elements for the entire width. Overall, it also sees much better.
I made a user control that fits my purpose but it can’t be virtualized and is really slow with the resize.
Here is my code for the adaptable UserControl.
<UserControl x:Class="ItemViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450"
d:DesignWidth="800"
Loaded="UserControl_Loaded"
x:Name="uc">
<Grid DataContext="{Binding ElementName=uc}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*"
x:Name="SecondRow" />
</Grid.RowDefinitions>
<TextBlock x:Name="Header"
Text="{Binding HeaderText,Mode=OneWay}"
Foreground="White"
HorizontalAlignment="Left"
Margin="0,0,0,10"
FontSize="28"
FontWeight="Medium" />
<ItemsControl Grid.Row="2"
x:Name="ListViewProducts"
SizeChanged="Grid_SizeChanged"
HorizontalAlignment="Stretch"
ItemsSource="{Binding Items,Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Height="{Binding Path=DataContext.ItemHeight, RelativeSource={RelativeSource AncestorType=ItemsControl},Mode=OneTime}"
MaxWidth="{Binding Path=DataContext.ItemMaxWidth, RelativeSource={RelativeSource AncestorType=ItemsControl},Mode=OneTime}"
Margin="0,0,10,10">
<Border Background="Beige"
CornerRadius="10" />
<!-- The specific UserControl or an element -->
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="2"
Initialized="UniformGrid_Initialized" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="HorizontalAlignment"
Value="Stretch" />
<Setter Property="VerticalAlignment"
Value="Top" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Grid>
</UserControl>
The code behind:
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Interop;
namespace MVVM.View.HomeView
{
/// <summary>
/// Interaktionslogik für ItemViewer.xaml
/// </summary>
public partial class ItemViewer : UserControl
{
private UniformGrid? _itemUniformGrid;
public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register(nameof(HeaderText), typeof(string), typeof(ItemViewer));
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set { SetValue(HeaderTextProperty, value); }
}
public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register("ItemHeight", typeof(double), typeof(ItemViewer));
public double ItemHeight
{
get { return (double)GetValue(ItemHeightProperty); }
set { SetValue(ItemHeightProperty, value); }
}
public static readonly DependencyProperty ItemMinWidthProperty = DependencyProperty.Register("ItemMinWidth", typeof(double), typeof(ItemViewer));
public double ItemMinWidth { get { return (double)GetValue(ItemMinWidthProperty); } set { SetValue(ItemMinWidthProperty, value); List_SizeChanged(); } }
public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register("ItemWidth", typeof(double), typeof(ItemViewer));
public double ItemWidth { get { return (double)GetValue(ItemWidthProperty); } set { SetValue(ItemWidthProperty, value); List_SizeChanged(); } }
public static readonly DependencyProperty ItemMaxWidthProperty = DependencyProperty.Register("ItemMaxWidth", typeof(double), typeof(ItemViewer));
public double ItemMaxWidth { get { return (double)GetValue(ItemMaxWidthProperty); } set { SetValue(ItemMaxWidthProperty, value); List_SizeChanged(); } }
private double row = 0;
public double Row { get { return row; } set { row = (value >= 0 ? value : 0); if (Row != 0) { SecondRow.MaxHeight = 10 * (Row - 1) + ItemHeight * Row; } } }
public ItemViewer()
{
InitializeComponent();
}
private int itemCounter = 0;
public ObservableCollection<object> Items
{
get { return (ObservableCollection<object>)GetValue(ItemsProperty); }
set => SetValue(ItemsProperty, value);
}
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register("Items", typeof(ObservableCollection<object>), typeof(ItemViewer));
private const int WmExitSizeMove = 0x232;
private IntPtr HwndMessageHook(IntPtr wnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case WmExitSizeMove:
List_SizeChanged();
handled = true;
break;
}
return IntPtr.Zero;
}
private void List_SizeChanged()
{
if (Items == null || Items.Count == 0 || _itemUniformGrid == null)
return;
itemCounter = Items.Count;
int columns = (int)(ListViewProducts.ActualWidth / (10 + ItemWidth));
if (columns <= itemCounter && ListViewProducts.ActualWidth < (ItemMaxWidth + 10) * columns)
{
if (_itemUniformGrid.HorizontalAlignment != HorizontalAlignment.Stretch)
{
_itemUniformGrid.ClearValue(WidthProperty);
_itemUniformGrid.HorizontalAlignment = HorizontalAlignment.Stretch;
}
if (columns != _itemUniformGrid.Columns)
_itemUniformGrid.Columns = columns;
}
else
{
if (columns >= itemCounter)
{
double newWidth;
newWidth = ListViewProducts.ActualWidth / itemCounter;
newWidth = newWidth > ItemMaxWidth ? ItemMaxWidth : newWidth;
_itemUniformGrid.Width = (newWidth + 10) * itemCounter;
_itemUniformGrid.HorizontalAlignment = HorizontalAlignment.Left;
_itemUniformGrid.Columns = itemCounter;
}
else
{
_itemUniformGrid.HorizontalAlignment = HorizontalAlignment.Left;
_itemUniformGrid.Columns = (int)(ListViewProducts.ActualWidth / (ItemMaxWidth + 10));
_itemUniformGrid.Width = (ItemMaxWidth + 10) * _itemUniformGrid.Columns;
}
}
}
private void UniformGrid_Initialized(object sender, EventArgs e) =>
_itemUniformGrid = (UniformGrid)sender;
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
List_SizeChanged();
if (Application.Current.MainWindow == null)
return;
WindowInteropHelper? helper = new(Application.Current.MainWindow);
HwndSource? source = HwndSource.FromHwnd(helper.Handle);
if (source != null)
source.AddHook(HwndMessageHook);
}
private int sizeP = 0;
private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (sizeP - e.NewSize.Width is < (-200) or > 200)
{
sizeP = (int)e.NewSize.Width;
List_SizeChanged();
}
else if (Application.Current.MainWindow.WindowState == WindowState.Maximized && sizeP != (int)e.NewSize.Width)
{
sizeP = (int)e.NewSize.Width;
List_SizeChanged();
}
}
}
}
Implementation:
<local:ItemViewer Items="{Binding Objects}"
HeaderText="Recent"
ItemMinWidth="200"
ItemWidth="350"
ItemHeight="150"
ItemMaxWidth="500"
Row="1" />
To make it more responsive I call the resized only when the resize finished. I think it doesn't break with mvvm because it is only for the UI. But in the end, it is quite a bad implementation.
So, is there a better way or good code on GitHub that has a similar behaviour? Here are a few Images of an implementation of my code:
The Width is set dynamically and it wraps when there is enough space.
Here my implementation of my UserControl. The Broders have a dynamic width and also can wrap, but is realy slow.
Here the same with a WrapPanel. Static width and fast wrapping
Problem
I want to refresh my wpf view when a change is made in a List of objects in my application, but it wont register the INotifyChanged method when I change a value.
What I've tried
I went to multiple different stackoverflow pages with sort of the same problem but I don't get it working right. It wont register a change in a object in the list.
my code
below is the code for the MainWindow of the WPF application in wher with the last button click I change the value of XLocation in an object out of a list.
public partial class MainWindow : Window
{
private string filePathArtist { get; set; }
private string filePathGrid { get; set; }
public Game.Game Game { get; set; }
public MainWindow()
{
InitializeComponent();
filePathGrid = String.Empty;
filePathArtist = String.Empty;
}
private void BtnOpen_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
bool? res = openFileDialog.ShowDialog();
if (res == true)
{
string filepathgrid = openFileDialog.FileName;
filePathGrid = filepathgrid;
GridTextBox.Text = filepathgrid;
}
}
private void PickArtistBtn_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
bool? res = openFileDialog.ShowDialog();
if (res == true)
{
string filepathartist = openFileDialog.FileName;
filePathArtist = filepathartist;
ArtistTextBox.Text = filepathartist;
}
}
private void CreateGridBtn_Click(object sender, RoutedEventArgs e)
{
Game = new Game.Game(filePathGrid, filePathArtist);
this.DataContext = Game;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Game.Artists[0].XLocation = 30;
}
}
Next code is the Game class where is implemented a INotfyPropertyChanged on the list of Artists.
public class Game : INotifyPropertyChanged
{
public List<Artist> _artists;
public List<Artist> Artists
{
get
{
return _artists;
}
set
{
_artists = value;
OnPropertyChanged("Artists");
}
}
public List<ITile> Tiles { get; set; }
public Game()
{
}
public Game(string graphPath, string artistPath)
{
IDataParser graphParser = DataFactory.DataFactory.Instance.CreateParser(graphPath);
IDataParser artistParser = DataFactory.DataFactory.Instance.CreateParser(artistPath);
Tiles = graphParser.ParseGridData(graphPath);
Artists = artistParser.ParseArtistData(artistPath);
Test = "new Game";
}
public string Test { get; set; } = "t";
public event PropertyChangedEventHandler? PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Ive also added the INotifyPropertyChanged in the Artists class
public class Artist : INotifyPropertyChanged
{
private float _xLocation;
private float _yLocation;
private int _xVelocity;
private int _yVelocity;
public float XLocation
{
get => _xLocation;
set
{
_xLocation = value;
OnPropertyChanged("XLocation");
}
}
public float ConvertedXLoc
{
get => XLocation * (float)3.75;
set { }
}
public float YLocation
{
get => _yLocation;
set
{
_yLocation = value;
OnPropertyChanged("YLocation");
}
}
public float ConvertedYLoc
{
get => YLocation * (float)3.75;
set { }
}
public int XVelocity
{
get => _xVelocity;
set
{
_xVelocity = value;
}
}
public int YVelocity
{
get => _yVelocity;
set
{
_yVelocity = value;
}
}
public event PropertyChangedEventHandler? PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Then here is the Xaml code where I bind the objects to the wpf UI.
<Window x:Class="BroadwayBoogie.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:game="clr-namespace:BroadwayBoogie.Game"
mc:Ignorable="d"
Title="MainWindow" Height="900" Width="900"
>
<Window.DataContext>
<game:Game/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="201*"/>
<ColumnDefinition Width="199*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="21*"/>
<RowDefinition Height="401*"/>
<RowDefinition Height="20*"/>
</Grid.RowDefinitions>
<Button x:Name="BtnOpen" Content="Pick Grid" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Click="BtnOpen_Click"/>
<TextBox x:Name="GridTextBox" HorizontalAlignment="Center" TextWrapping="NoWrap" VerticalAlignment="Center" Width="266" />
<Button x:Name="PickArtistBtn" Content="Pick Artist" HorizontalAlignment="Left" Margin="356,0,0,0" VerticalAlignment="Center" Click="PickArtistBtn_Click" RenderTransformOrigin="-0.135,0.647"/>
<TextBox x:Name="ArtistTextBox" HorizontalAlignment="Left" Margin="30,14,0,0" TextWrapping="NoWrap" VerticalAlignment="Top" Width="231" Grid.Column="1"/>
<Button x:Name="CreateGridBtn" Grid.Column="1" Content="Create Grid" HorizontalAlignment="Left" Margin="311,14,0,0" VerticalAlignment="Top" Click="CreateGridBtn_Click"/>
<Canvas Width="800" Height="800" Grid.ColumnSpan="2" Margin="49,15,51,27" Grid.Row="1" Background="DarkSeaGreen" Grid.RowSpan="2">
<ItemsControl Name="tilesItemsControl" ItemsSource="{Binding Tiles}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<Rectangle
Width="15"
Height="15"
Fill="{Binding Color}"
Canvas.Left ="{Binding ConvertedXLoc}"
Canvas.Top="{Binding ConvertedYLoc}" />
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Name="ArtistItemsControl" ItemsSource="{Binding Artists}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<Rectangle
Width="3.75"
Height="3.75"
Fill="Black"
Canvas.Left ="{Binding ConvertedXLoc}"
Canvas.Top="{Binding ConvertedYLoc}" />
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
<Grid/>
<Button Content="Button" HorizontalAlignment="Left" Margin="4,0,0,0" Grid.Row="2" VerticalAlignment="Center" Click="Button_Click"/>
</Grid>
So with the press of the button I added for testing purposes. It changes a value in the List and then the PropertyChanged method should detect that but it doesn't detect it it just skips it.
Question
So my basic question is, how do I detect the change of a property from objects out of the List of Artists.
OnPropertyChanged will only be executed when the property itself is changed. A new item in a list is not a property change. That's the reason why no updates happens.
Instead a List, try an ObservableCollection. An ObservableCollection implements an additional INotifyCollectionChanged which makes the UI able to react on changing items in the list.
I want to drow so many graphs with OxyPlot Library.
And I'm testing now that I can add how many graphs with dynamic (but I'll not add graphs over 10000 graphs because it's max graphs in real application).
However when I'll add over 200 graphs, the Oxyplot throw exception.
Exception message is "This PlotModel is already in use by some other PlotView control.".
There are all of my code. (In code, I add graph with dynamic and I add values to the all graphs each 5 second in other thread.)
//Xaml -- MainView
<Window x:Class="OxyplotStressTest.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:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf"
xmlns:local="clr-namespace:OxyplotStressTest"
mc:Ignorable="d"
Title="MainWindow" Height="550" Width="725">
<Grid>
<Button Content="Add 100" HorizontalAlignment="Left" Height="32" Margin="20,23,0,0" VerticalAlignment="Top" Width="65" Click="Button_Click100"/>
<Button Content="Add 50" HorizontalAlignment="Left" Height="32" Margin="102,23,0,0" VerticalAlignment="Top" Width="65" Click="Button_Click50"/>
<Button Content="Add 10" HorizontalAlignment="Left" Height="32" Margin="189,23,0,0" VerticalAlignment="Top" Width="65" Click="Button_Click10"/>
<Button Content="Add 1" HorizontalAlignment="Left" Height="32" Margin="274,23,0,0" VerticalAlignment="Top" Width="65" Click="Button_Click1"/>
<Grid Margin="20,65,19,10">
<ScrollViewer>
<ItemsControl ItemsSource="{Binding List}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding Tag}"/>
<oxy:PlotView HorizontalAlignment="Left" Height="130" Margin="20,23,0,0" VerticalAlignment="Top" Width="600"
Model="{Binding Chart}" IsMouseWheelEnabled="False" IsManipulationEnabled="False" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Grid>
//C# -- MainWindow.cs
public partial class MainWindow : Window
{
private MainWindowViewModel mMainWindowViewModel = null;
public MainWindow()
{
InitializeComponent();
MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
this.DataContext = mainWindowViewModel;
mMainWindowViewModel = mainWindowViewModel;
Thread thread = new Thread(new ParameterizedThreadStart(reloadGraph));
thread.Start();
}
private void Button_Click100(object sender, RoutedEventArgs e)
{
AddGraph addGraph = new AddGraph(mMainWindowViewModel);
addGraph.addGraph(100);
}
private void Button_Click50(object sender, RoutedEventArgs e)
{
AddGraph addGraph = new AddGraph(mMainWindowViewModel);
addGraph.addGraph(50);
}
private void Button_Click10(object sender, RoutedEventArgs e)
{
AddGraph addGraph = new AddGraph(mMainWindowViewModel);
addGraph.addGraph(10);
}
private void Button_Click1(object sender, RoutedEventArgs e)
{
AddGraph addGraph = new AddGraph(mMainWindowViewModel);
addGraph.addGraph(1);
}
private void reloadGraph(object param)
{
while (true)
{
Thread.Sleep(5000);
if (mMainWindowViewModel.List.Count > 0)
{
AddGraph addGraph = new AddGraph(mMainWindowViewModel);
addGraph.reloadGraph();
}
Console.WriteLine(Environment.WorkingSet.ToString());
}
}
}
//C# -- MainViewModel
public MainWindowViewModel()
{
listVal = new ObservableCollection<Items>();
BindingOperations.EnableCollectionSynchronization(this.listVal, new object());
}
private ObservableCollection<Items> listVal = new ObservableCollection<Items>();
public ObservableCollection<Items> List
{
get
{
return listVal;
}
set
{
listVal = value;
NotifyPropertyChanged("List");
}
}
public class Items
{
public string Tag { get; set; }
private PlotModel chartVal = new PlotModel();
public PlotModel Chart
{
get
{
return chartVal;
}
set
{
chartVal = value;
}
}
}
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
//C# -- Model Class
class AddGraph
{
private MainWindowViewModel mMainWindowViewModel = null;
public AddGraph(MainWindowViewModel pMainWindowViewModel)
{
mMainWindowViewModel = pMainWindowViewModel;
}
public void addGraph(int pCount)
{
try
{
for (int i = 0; i < pCount; i++)
{
Random random = new Random();
long data = random.Next(100);
ColumnSeries column = new ColumnSeries();
column.FillColor = OxyColors.SkyBlue;
column.Items.Add(new ColumnItem() { Value = data });
data *= random.Next(50);
column.Items.Add(new ColumnItem() { Value = data });
Items items = new Items();
items.Tag = mMainWindowViewModel.List.Count.ToString();
items.Chart.Series.Add(column);
items.Chart.InvalidatePlot(true);
mMainWindowViewModel.List.Add(items);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public void reloadGraph()
{
try
{
List<Items> newList = new List<Items>();
foreach (Items listItem in mMainWindowViewModel.List)
{
string tag = listItem.Tag;
PlotModel plotModel = listItem.Chart;
ColumnSeries oldGraph = (ColumnSeries)plotModel.Series[0];
ColumnSeries newGraph = new ColumnSeries();
newGraph.FillColor = OxyColors.SkyBlue;
for (int i = 0; i < oldGraph.Items.Count; i++)
{
if (oldGraph.Items.Count == 30 && i == 0)
{
continue;
}
newGraph.Items.Add(new ColumnItem() { Value = oldGraph.Items[i].Value });
}
Random random = new Random();
long val = random.Next(500);
val *= random.Next(50);
newGraph.Items.Add(new ColumnItem() { Value = val });
Items items = new Items();
items.Tag = tag;
items.Chart.Series.Add(newGraph);
items.Chart.InvalidatePlot(true);
newList.Add(items);
}
#region //there are my solution and it shows good performance
int index = 0;
foreach (var addItem in newList)
{
mMainWindowViewModel.List[index] = addItem;
index++;
}
#endregion
#region //there are my first code and it has problem
mMainWindowViewModel.List.Clear();
foreach (var addItem in newList)
{
mMainWindowViewModel.List.Add(addItem);
}
#endregion
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
Maybe my code is bad, but I don't know where is the bad code because it dosen't stop on BreakPoint.
If you give me a advice, I'm so glad.
I think you may need to rebuild it a little using idea from OxyPlot Example: https://github.com/oxyplot/oxyplot/tree/develop/Source/Examples/WPF/WpfExamples
When i were working last months with oxyplots i found out that this official examples are well done with they ideas, they solution with Performance Demo using this virtualization may helps with performance:
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsVirtualizing="True" IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
The problem may cause using NotifyPropertyChange as refreshing UI as adding new chart maybe you should somehow Unbind List > Notify > Bind New List.
Check more in the link and try to mash-ups they solution to make your own :)
I glad if i have helped some :)
I have developed a user control. The user control is like a magnifier glass .
The user control has an image button which shows images cropped pixel by pixel .
StorageFile storageFile =
await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/wallpaper.jpg", UriKind.RelativeOrAbsolute));
using (Windows.Storage.Streams.IRandomAccessStream fileStream = await storageFile.OpenAsync(FileAccessMode.Read))
{
BitmapImage bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
WriteableBitmap writeableBitmap =
new WriteableBitmap(bitmapImage.PixelWidth, bitmapImage.PixelHeight);
fileStream.Seek(0);
await writeableBitmap.SetSourceAsync(fileStream);
writeableBitmap = writeableBitmap.Crop(Convert.ToInt32(xValue), Convert.ToInt32(yValue), 100, 100);
MagnifyTip.image1.ImageSource = writeableBitmap;
Now the MagnifyTip.image1 has an image source that is set to a cropped image .
My requirenment is to zoom the cropped region and then assign it to the image source.
The user control looks like this
Help would be appreciated
Maybe this works for you, it is as efficient as WPF allows I suppose since there is no image cropping in the code, it just uses the RenderTransform to do the magic. Run the code below and press the mouse over the image so the magnifying glass appears like this:
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Width="512"
Height="512">
<Grid>
<Canvas MouseDown="FullImage_OnMouseDown"
MouseMove="FullImage_OnMouseMove"
MouseUp="FullImage_OnMouseUp">
<Image Name="FullImage"
Source="http://www.mupin.it/wp-content/uploads/2012/06/lenna1.png" />
<Border Name="BorderZoom"
Visibility="Visible"
Width="{Binding ImageZoomSize, FallbackValue='200'}"
Height="{Binding ImageZoomSize, FallbackValue='200'}">
<Border.Clip>
<EllipseGeometry RadiusX="{Binding ImageZoomSizeHalf, FallbackValue=100}"
RadiusY="{Binding ImageZoomSizeHalf, FallbackValue=100}"
Center="{Binding CenterPoint, FallbackValue='100,100'}">
</EllipseGeometry>
</Border.Clip>
<Image Source="{Binding ElementName=FullImage, Path=Source}"
RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<TransformGroup>
<TranslateTransform X="{Binding Xt}"
Y="{Binding Yt}" />
<ScaleTransform ScaleX="{Binding ZoomFactor, FallbackValue='8'}"
ScaleY="{Binding ZoomFactor, FallbackValue='8'}" />
</TransformGroup>
</Image.RenderTransform>
</Image>
</Border>
</Canvas>
</Grid>
</Window>
And this is the code behind:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
namespace WpfApplication1
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
ZoomFactor = 8;
ImageZoomSize = 200;
InitializeComponent();
BorderZoom.Visibility = Visibility.Hidden;
}
public double Xt { get; private set; }
public double Yt { get; private set; }
public double ZoomFactor { get; private set; }
public int ImageZoomSize { get; private set; }
public int ImageZoomSizeHalf { get { return ImageZoomSize/2; } }
public Point CenterPoint { get { return new Point(ImageZoomSizeHalf, ImageZoomSizeHalf);} }
private void FullImage_OnMouseDown(object sender, MouseButtonEventArgs e)
{
BorderZoom.Visibility = Visibility.Visible;
FullImage_OnMouseMove(sender, e);
}
private void FullImage_OnMouseMove(object sender, MouseEventArgs e)
{
if (BorderZoom.Visibility == Visibility.Visible)
{
BorderZoom.Visibility = Visibility.Visible;
var pos = e.GetPosition(FullImage);
Canvas.SetLeft(BorderZoom, pos.X - ImageZoomSizeHalf);
Canvas.SetTop(BorderZoom, pos.Y - ImageZoomSizeHalf);
var isrc = FullImage.Source as BitmapSource;
if(isrc == null) return;
var h = (double)isrc.PixelHeight;
var w = (double)isrc.PixelWidth;
Xt = pos.X* (-ImageZoomSize/w) + ImageZoomSize/2.0;
Yt = pos.Y * (-ImageZoomSize / h) + ImageZoomSize / 2.0;
OnNotifyPropertyChanged("Xt");
OnNotifyPropertyChanged("Yt");
}
}
private void FullImage_OnMouseUp(object sender, MouseButtonEventArgs e)
{
BorderZoom.Visibility = Visibility.Hidden;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnNotifyPropertyChanged(string propName)
{
if(PropertyChanged!= null) PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
UPDATE
As requested see the code below wrapping the magnifying tip in a user control that looks like this:
XAML for MagifiyingTipCtrl:
<UserControl x:Class="WpfApplication1.MagifiyingTipCtrl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid Name="ZoomedArea" VerticalAlignment="Top"
Visibility="Visible"
Margin="15,15"
Width="{Binding ZoomWidth, FallbackValue='136'}"
Height="{Binding ZoomHeight, FallbackValue='128'}">
<Grid.Clip>
<EllipseGeometry RadiusX="{Binding ZoomWidthHalf, FallbackValue=68}"
RadiusY="{Binding ZoomHeightHalf, FallbackValue=64}"
Center="{Binding CenterPoint, FallbackValue='100,100'}">
</EllipseGeometry>
</Grid.Clip>
<Image Source="{Binding SourceImage}"
RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<TransformGroup>
<TranslateTransform X="{Binding Xt}"
Y="{Binding Yt}" />
<ScaleTransform ScaleX="{Binding ZoomFactor, FallbackValue='8'}"
ScaleY="{Binding ZoomFactor, FallbackValue='8'}" />
</TransformGroup>
</Image.RenderTransform>
</Image>
</Grid>
<Path Data="M25.533,0C15.457,0,7.262,8.199,7.262,18.271c0,9.461,13.676,19.698,17.63,32.338 c0.085,0.273,0.34,0.459,0.626,0.457c0.287-0.004,0.538-0.192,0.619-0.467c3.836-12.951,17.666-22.856,17.667-32.33 C43.803,8.199,35.607,0,25.533,0z M25.533,32.131c-7.9,0-14.328-6.429-14.328-14.328c0-7.9,6.428-14.328,14.328-14.328 c7.898,0,14.327,6.428,14.327,14.328C39.86,25.702,33.431,32.131,25.533,32.131z"
Fill="#FFF4F4F5"
Stretch="Fill"
Stroke="Black"
UseLayoutRounding="False"
Height="227"
Width="171" />
</Grid>
</UserControl>
Code-behind for MagifiyingTipCtrl:
using System.Windows.Media.Imaging;
namespace WpfApplication1
{
public partial class MagifiyingTipCtrl : UserControl
{
public MagifiyingTipCtrl()
{
ZoomFactor = 8;
ZoomWidth = 136;
ZoomHeight = 128;
InitializeComponent();
}
public static readonly DependencyProperty SourceImageProperty =
DependencyProperty.Register("SourceImage", typeof (BitmapSource), typeof (MagifiyingTipCtrl));
public static readonly DependencyProperty XtProperty =
DependencyProperty.Register("Xt", typeof(double), typeof(MagifiyingTipCtrl));
public static readonly DependencyProperty YtProperty =
DependencyProperty.Register("Yt", typeof(double), typeof(MagifiyingTipCtrl));
public BitmapSource SourceImage
{
get { return (BitmapSource)GetValue(SourceImageProperty); }
set { SetValue(SourceImageProperty, value); }
}
public double Xt
{
get { return (double)GetValue(XtProperty); }
set { SetValue(XtProperty, value); }
}
public double Yt
{
get { return (double)GetValue(YtProperty); }
set { SetValue(YtProperty, value); }
}
public void SetPosition(Point pos)
{
if (SourceImage == null) return;
var h = (double)SourceImage.PixelHeight;
var w = (double)SourceImage.PixelWidth;
Xt = pos.X * (-ZoomWidth / w) + ZoomWidth / 2.0;
Yt = pos.Y * (-ZoomHeight / h) + ZoomHeight / 2.0;
}
public double ZoomFactor { get; private set; }
public int ZoomWidth { get; private set; }
public int ZoomHeight { get; private set; }
public int ZoomWidthHalf { get { return ZoomWidth / 2; } }
public int ZoomHeightHalf { get { return ZoomHeight / 2; } }
public Point CenterPoint { get { return new Point(ZoomWidthHalf, ZoomHeightHalf); } }
}
}
XAML for the MainWindow:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication1="clr-namespace:WpfApplication1"
Title="MainWindow"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Width="512"
Height="512">
<Grid>
<Canvas MouseDown="FullImage_OnMouseDown"
MouseMove="FullImage_OnMouseMove"
MouseUp="FullImage_OnMouseUp">
<Image Name="FullImage"
Source="http://www.mupin.it/wp-content/uploads/2012/06/lenna1.png" />
<wpfApplication1:MagifiyingTipCtrl x:Name="MagnifiyingTip"
SourceImage="{Binding ElementName=FullImage, Path=Source}" />
</Canvas>
</Grid>
</Window>
Code-behind for MainWindow:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void FullImage_OnMouseDown(object sender, MouseButtonEventArgs e)
{
MagnifiyingTip.Visibility = Visibility.Visible;
FullImage_OnMouseMove(sender, e);
}
private void FullImage_OnMouseMove(object sender, MouseEventArgs e)
{
if (MagnifiyingTip.Visibility == Visibility.Visible)
{
MagnifiyingTip.Visibility = Visibility.Visible;
var pos = e.GetPosition(FullImage);
Canvas.SetLeft(MagnifiyingTip, pos.X - MagnifiyingTip.ActualWidth/2);
Canvas.SetTop(MagnifiyingTip, pos.Y - MagnifiyingTip.ActualHeight);
MagnifiyingTip.SetPosition(pos);
}
}
private void FullImage_OnMouseUp(object sender, MouseButtonEventArgs e)
{
MagnifiyingTip.Visibility = Visibility.Hidden;
}
}
}
Just as i wrote in my comment, a quick demoapp in WPF for your PictureZoom.
https://github.com/hrkrx/PictureZoomExample
its just an examle so there can be a lot optimized, but i hope it is helping you
I have structured the classes like this for my Universal app. Currently working in the WP8.1 part.
The following classes are put in the shared code. (Hoping to use it in Win8.1)
FolderItemViewer.xaml(UserControl) It is the DataTemplate for a ListView in the MainPage.xaml
FolderCollection class, which is the collection that is bound to the Listview in the Mainpage.xaml of the WP
Now the problem is, I have wired the manipulation events to the datatemplate grids in the FolderItemViewer.xaml to capture the right and left swipe and it is working. Now based on this, I need to update that CollectionItem in FolderCollection class and hence the ListView in Mainpage.xaml.
How do I capture that listview item or the collectionitem bound since the manipulation events lie in the FolderItemViewer class?
Can I get the listview item? Or a call back function to the listlivew item template changed? or somethin like that?
EDIT
Sorry to put in so much code. But really appreciate somebody's help in getting this right.
This is the FolderItemViewer.xaml
<UserControl
x:Class="JusWrite2.FolderItemViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:JusWrite2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid x:Name="MainGrid">
<Grid Height="60" Width="380" Margin="0,0,0,1">
<Grid x:Name="ItemGrid" HorizontalAlignment="Left" VerticalAlignment="Center" Width="380" Height="60" Background="Transparent" Canvas.ZIndex="2"
ManipulationMode="TranslateX,System" ManipulationStarted="On_ChannelItem_ManipulationStarted" ManipulationDelta="On_ChannelItem_ManipulationDelta" ManipulationCompleted="OnChannelItemManipulationCompleted">
<TextBlock x:Name="titleTextBlock" Margin="20,0,0,0" Canvas.ZIndex="2" VerticalAlignment="Center" TextAlignment="Left" FontSize="25" >
</TextBlock>
</Grid>
<Grid x:Name="DelGrid" Opacity="0.0" HorizontalAlignment="Right" VerticalAlignment="Center" Height="60" Background="Red" Canvas.ZIndex="-1" Tapped="On_ChannelDelete_Tap" Width="380">
<Button Content="X" FontSize="25" Canvas.ZIndex="-1" VerticalAlignment="Center" HorizontalAlignment="Center" Width="380" BorderThickness="0" />
</Grid>
</Grid>
</Grid>
</UserControl>
code behind
private void OnChannelItemManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
{
Grid ChannelGrid = (Grid)sender;
Grid mGrid = (Grid)(ChannelGrid.Parent);
Grid DeleteGrid = (Grid)((Grid)(ChannelGrid.Parent)).Children[1];
FolderCollection swipedItem = ChannelGrid.DataContext as FolderCollection;// grid has null value for datacontext
double dist = e.Cumulative.Translation.X;
if (dist < -100)
{
// Swipe left
}
else
{
// Swipe right
}
}
FolderCollection.xaml has two classes in it. FolderItem and FolderCollection
public class FolderItem : INotifyPropertyChanged
{
// variables
public FolderItem()
{
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public int CompletionStatus
{
//code
}
public int Priority
{
//code
}
public string FolderText
{
//code
}
public int PenColor
{
//code
}
public string UUID
{
//code
}
public string CreateUUID()
{
//code
}
}
public class FolderCollection : IEnumerable<Object>
{
private ObservableCollection<FolderItem> folderCollection = new ObservableCollection<FolderItem>();
private static readonly FolderCollection instance = new FolderCollection();
public static FolderCollection Instance
{
get
{
return instance;
}
}
public IEnumerator<Object> GetEnumerator()
{
return folderCollection.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(FolderItem fItem)
{
folderCollection.Add(fItem);
}
public ObservableCollection<FolderItem> FolderCollectionInstance
{
get
{
return folderCollection;
}
}
}
And this is the MainPage.xaml where I have data bound.
// Resources
<DataTemplate x:Key="StoreFrontTileTemplate">
<local:FolderItemViewer />
</DataTemplate>
<ListView x:Name="FolderListView" ItemsSource="{Binding}"
SelectionMode="None"
ItemTemplate="{StaticResource StoreFrontTileTemplate}"
ContainerContentChanging="ItemListView_ContainerContentChanging">
</ListView>
code behind
//Constructor
FolderListView.DataContext = fc.FolderCollectionInstance;
FolderListView.ItemsSource = fc.FolderCollectionInstance;
private void ItemListView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
FolderItemViewer iv = args.ItemContainer.ContentTemplateRoot as FolderItemViewer;
if (args.InRecycleQueue == true)
{
iv.ClearData();
}
else if (args.Phase == 0)
{
iv.ShowPlaceholder(args.Item as FolderItem);
// Register for async callback to visualize Title asynchronously
args.RegisterUpdateCallback(ContainerContentChangingDelegate);
}
else if (args.Phase == 1)
{
iv.ShowTitle();
args.RegisterUpdateCallback(ContainerContentChangingDelegate);
}
else if (args.Phase == 2)
{
//iv.ShowCategory();
//iv.ShowImage();
}
// For imporved performance, set Handled to true since app is visualizing the data item
args.Handled = true;
}
private TypedEventHandler<ListViewBase, ContainerContentChangingEventArgs> ContainerContentChangingDelegate
{
get
{
if (_delegate == null)
{
_delegate = new TypedEventHandler<ListViewBase, ContainerContentChangingEventArgs>(ItemListView_ContainerContentChanging);
}
return _delegate;
}
}
private TypedEventHandler<ListViewBase, ContainerContentChangingEventArgs> _delegate;
The list item should be available as the data context of the grid: ChannelGrid.DataContext.