This question already has answers here:
Polyline using DataBinding and PointCollection for continuous update
(3 answers)
After WPF Polygon binding, the graphics remain unchanged
(1 answer)
Closed 5 months ago.
I try to create dynamic polyline and add points by timer. But I have problems with addition points to PointCollection array and display them in view. I tried fix it with "Application.Current.Dispatcher.BeginInvoke" but it still doesn't work. How can I fix this?
Xaml code:
<Grid Width="800" Height="100">
<Polyline StrokeThickness="5" Stroke="Gray" Points="{Binding FPoint}"></Polyline>
</Grid>
ViewModel code:
private Timer _timer;
private int x = 0;
private PointCollection _fPoint = new PointCollection();
public PointCollection FPoint
{
get => _fPoint ;
set => SetProperty(ref _fPoint , value);
}
public FViewModel()
{
_timer = new Timer { Enabled = true, Interval = 4000 };
_timer.Elapsed += TimerAction;
}
public void TimerAction(object state, ElapsedEventArgs e)
{
x += 10;
Application.Current.Dispatcher.BeginInvoke((Action)(() => { FPoint.Add(new Point(x, Generation())); }));
}
Related
This question already has answers here:
How do you bind a grid's children to a list?
(1 answer)
WPF Grid as ItemsPanel for a list dynamically bound to an ItemsControl
(3 answers)
Closed last year.
For the purpose of learning MVVM and WPF (I am fairly new to both these), I am building a simple game.
The game board consists of 9 (3x3) tiles (I want to have it NxN later on, but 3x3 is good enough for the example), which need to be evenly placed next to each other in three rows.
I have defined an user control for the tiles as shown below in the View XAML.
The problem: while my data bindings work fine, I have been unable to find a layout where I could place my UserControls, as I cannot use ItemsSource and ItemTemplate with a Grid or a Canvas.
Since the game tiles might change their (PositionX and PositionY), I am looking for a layout that could support placement of user controls in X and Y coordinates, something like Grid.Column and Grid.Row (or Canvas.Left and .Top properties).
P.S. Never mind the ListBox, it is there just to make sure the data bindings worked and the tile value was displayed on the tiles.
View XAML:
<UserControl.Resources>
<DataTemplate x:Key="TileTemplate">
<Border x:Name="GamePieceItem" BorderThickness="2" BorderBrush="DimGray"
CornerRadius="5" Background="LightYellow" Height="60" Width="60"
Grid.Column="{Binding Path=PositionX, Mode=TwoWay}"
Grid.Row="{Binding Path=PositionY, Mode=TwoWay}">
<TextBlock Text="{Binding Path=TileValue, Mode=TwoWay}" FontSize="40" FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center"
x:Name="ValueField"
Margin="2"
/>
</Border>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ListBox ItemsSource="{Binding GameTiles}"
ItemTemplate="{StaticResource TileTemplate}"/>
</Grid>
</UserControl>
Model:
public class GameTile : INotifyPropertyChanged
{
private int _positionx;
private int _positiony;
private int _tilevalue;
public int PositionX
{
get { return _positionx; }
set
{
_positionx = value;
RaisePropertyChanged("PositionX");
}
}
public int PositionY
{
get { return _positiony; }
set
{
_positiony = value;
RaisePropertyChanged("PositionY");
}
}
public int TileValue
{
get
{ return _tilevalue; }
set
{
_tilevalue = value;
RaisePropertyChanged("TileValue");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}
ViewModel:
public class GameTileViewModel
{
public ObservableCollection<GameTile> GameTiles
{
get;
set;
}
public void CreateBoard()
{
ObservableCollection<GameTile> gametiles = new ObservableCollection<GameTile>();
// the game board should be auto-generated in a loop, these are just two examples of the tiles
gametiles.Add(new GameTile { SequencePosition = 0, PositionX = 0, PositionY = 0, TileValue = 3 });
gametiles.Add(new GameTile { SequencePosition = 1, PositionX = 1, PositionY = 1, TileValue = 5 });
GameTiles = gametiles;
}
}
MainWindow XAML:
<Grid>
<views:GameBoardView x:Name="GameBoard" Loaded="GameBoard_Loaded"/>
</Grid>
MainWindow code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void GameBoard_Loaded(object sender, RoutedEventArgs e)
{
GameTileViewModel GameBoardObject = new GameTileViewModel();
GameBoardObject.CreateBoard();
GameBoard.DataContext = GameBoardObject;
}
}
I am trying to replicate the default Windows 10 behavior for touch-and-drag vs touch-hold-and-drag manipulations in WPF. Why this isn't already part of the framework in 2021, only MS overlords can tell us, but after searching the internet high and low, trying varios implementations, trying to shoehorn the UWP framework in my WPF app, etc., I decided to try and implement it myself.
To better illustrate what I am after and ensure we're on the same page, I've attached the following clips to demonstrate:
Touch and immediately drag
Touch, hold, then drag
Directory content is scrolled
Touched folder is dragged
I got to a point where it looks like my method will work, however ManipulationDelta event for elements which are placed inside a scroll viewer with Panning mode set to VerticalOnly only seem to provide values for Translation.Y, Translation.X being always 0. Obviously, my fingers won't move just perfectly vertically on the screen, so I would like to receive values for both axes.
In order to achieve this, I created a couple of custom controls, the first of which exposes the ManipulationDelta property which I can bind to so that I can provide the values to other controls. It also allows me to update the control's RenderTransform in the ManipulationDeltaCallback method so that the controls position on screen changes:
public class Manipulatable : UserControl
{
public static readonly DependencyProperty ManipulationDeltaProperty =
DependencyProperty.Register("ManipulationDelta", typeof(ManipulationDelta), typeof(Manipulatable), new PropertyMetadata(null, new PropertyChangedCallback(ManipulationDeltaCallback)));
private TransformGroup _transformGroup;
private TranslateTransform _translation;
//private ScaleTransform scale;
//private RotateTransform rotation;
public Manipulatable()
{
_transformGroup = new TransformGroup();
_translation = new TranslateTransform(0, 0);
//scale = new ScaleTransform(1, 1);
//rotation = new RotateTransform(0);
_transformGroup.Children.Add(_translation);
//transformGroup.Children.Add(scale);
//transformGroup.Children.Add(rotation);
RenderTransform = _transformGroup;
}
public new ManipulationDelta ManipulationDelta
{
get => (ManipulationDelta)GetValue(ManipulationDeltaProperty);
set => SetValue(ManipulationDeltaProperty, value);
}
private static void ManipulationDeltaCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var manipulationDelta = e.NewValue as ManipulationDelta;
var manipulatable = d as Manipulatable;
manipulatable._translation.X += manipulationDelta.Translation.X;
manipulatable._translation.Y += manipulationDelta.Translation.Y;
}
}
The second class exposes properties for all of the relevant touch manipulations events, again, so I can bind to them, as well as the touch and hold functionality which WPF is lacking for God knows what reason:
public class TouchAndHold : Manipulatable
{
public static readonly DependencyProperty TouchedAndHeldProperty =
DependencyProperty.Register("TouchedAndHeld", typeof(RelayCommand), typeof(TouchAndHold), new PropertyMetadata(null));
public static readonly DependencyProperty TouchedAndHeldParamProperty =
DependencyProperty.Register("TouchedAndHeldParam", typeof(object), typeof(TouchAndHold), new PropertyMetadata(null));
public static readonly DependencyProperty ManipulationStartingProperty =
DependencyProperty.Register("ManipulationStarting", typeof(RelayCommand<TouchAndHoldEventArgs>), typeof(TouchAndHold), new PropertyMetadata(null));
public static readonly DependencyProperty ManipulationStartedProperty =
DependencyProperty.Register("ManipulationStarted", typeof(RelayCommand<TouchAndHoldEventArgs>), typeof(TouchAndHold), new PropertyMetadata(null));
public static readonly DependencyProperty ManipulationDeltaChangedProperty =
DependencyProperty.Register("ManipulationDeltaChanged", typeof(RelayCommand<TouchAndHoldEventArgs>), typeof(TouchAndHold), new PropertyMetadata(null));
public static readonly DependencyProperty ManipulationCompletedProperty =
DependencyProperty.Register("ManipulationCompleted", typeof(RelayCommand<TouchAndHoldEventArgs>), typeof(TouchAndHold), new PropertyMetadata(null));
private double length;
private bool _overrideTouch;
private bool _held;
private DispatcherTimer _touchHoldTimer;
public TouchAndHold()
{
IsManipulationEnabled = true;
_touchHoldTimer = new DispatcherTimer();
_touchHoldTimer.Tick += _touchHoldTimer_Tick;
_touchHoldTimer.Interval = new TimeSpan(5000000);
}
public RelayCommand TouchedAndHeld
{
get { return (RelayCommand)GetValue(TouchedAndHeldProperty); }
set { SetValue(TouchedAndHeldProperty, value); }
}
public object TouchedAndHeldParam
{
get { return GetValue(TouchedAndHeldParamProperty); }
set { SetValue(TouchedAndHeldParamProperty, value); }
}
public new RelayCommand<TouchAndHoldEventArgs> ManipulationStarting
{
get { return (RelayCommand<TouchAndHoldEventArgs>)GetValue(ManipulationStartingProperty); }
set { SetValue(ManipulationStartingProperty, value); }
}
public new RelayCommand<TouchAndHoldEventArgs> ManipulationStarted
{
get { return (RelayCommand<TouchAndHoldEventArgs>)GetValue(ManipulationStartedProperty); }
set { SetValue(ManipulationStartedProperty, value); }
}
public RelayCommand<TouchAndHoldEventArgs> ManipulationDeltaChanged
{
get { return (RelayCommand<TouchAndHoldEventArgs>)GetValue(ManipulationDeltaChangedProperty); }
set { SetValue(ManipulationDeltaChangedProperty, value); }
}
public new RelayCommand<TouchAndHoldEventArgs> ManipulationCompleted
{
get { return (RelayCommand<TouchAndHoldEventArgs>)GetValue(ManipulationCompletedProperty); }
set { SetValue(ManipulationCompletedProperty, value); }
}
protected override void OnPreviewTouchDown(TouchEventArgs e)
{
length = 0;
_held = false;
_overrideTouch = true;
_touchHoldTimer.Start();
}
protected override void OnPreviewTouchUp(TouchEventArgs e)
{
e.Handled = !_overrideTouch || _held;
_held = false;
_overrideTouch = false;
_touchHoldTimer.Stop();
}
protected override void OnManipulationStarting(ManipulationStartingEventArgs e)
{
e.Handled = !_overrideTouch || _held;
ManipulationStarting?.Execute(new TouchAndHoldEventArgs(_overrideTouch, _held, e));
}
protected override void OnManipulationStarted(ManipulationStartedEventArgs e)
{
e.Handled = !_overrideTouch || _held;
ManipulationStarted?.Execute(new TouchAndHoldEventArgs(_overrideTouch, _held, e));
}
protected override void OnManipulationDelta(ManipulationDeltaEventArgs e)
{
if (_held)
{
e.Handled = true;
ManipulationDeltaChanged?.Execute(new TouchAndHoldEventArgs(_overrideTouch, _held, e));
return;
}
length += e.DeltaManipulation.Translation.Length;
if (length >= 10)
{
_overrideTouch = false;
_touchHoldTimer.Stop();
return;
}
e.Handled = !_overrideTouch || _held;
}
protected override void OnManipulationCompleted(ManipulationCompletedEventArgs e)
{
e.Handled = !_overrideTouch || _held;
ManipulationCompleted?.Execute(new TouchAndHoldEventArgs(_overrideTouch, _held, e));
}
private void _touchHoldTimer_Tick(object sender, EventArgs e)
{
_held = true;
_overrideTouch = false;
_touchHoldTimer.Stop();
TouchedAndHeld?.Execute(TouchedAndHeldParam);
}
public class TouchAndHoldEventArgs
{
public TouchAndHoldEventArgs(bool isTouchOverriden, bool isHeld, ManipulationStartingEventArgs eventArgs)
{
IsTouchOverriden = IsTouchOverriden;
IsHeld = isHeld;
ManipulationStartingEventArgs = eventArgs;
}
public TouchAndHoldEventArgs(bool isTouchOverriden, bool isHeld, ManipulationStartedEventArgs eventArgs)
{
IsTouchOverriden = isTouchOverriden;
IsHeld = isHeld;
ManipulationStartedEventArgs = eventArgs;
}
public TouchAndHoldEventArgs(bool isTouchOverriden, bool isHeld, ManipulationDeltaEventArgs eventArgs)
{
IsTouchOverriden = isTouchOverriden;
IsHeld = isHeld;
ManipulationDeltaEventArgs = eventArgs;
}
public TouchAndHoldEventArgs(bool isTouchOverriden, bool isHeld, ManipulationCompletedEventArgs eventArgs)
{
IsTouchOverriden = isTouchOverriden;
IsHeld = isHeld;
ManipulationCompletedEventArgs = eventArgs;
}
public bool IsTouchOverriden { get; }
public bool IsHeld { get; }
public ManipulationStartingEventArgs ManipulationStartingEventArgs { get; }
public ManipulationStartedEventArgs ManipulationStartedEventArgs { get; }
public ManipulationDeltaEventArgs ManipulationDeltaEventArgs { get; }
public ManipulationCompletedEventArgs ManipulationCompletedEventArgs { get; }
}
}
The touch and hold functionality works by having a boolean which, when set to true, ensures that all manipulation events are set handled (e.Handled = true). This ensures that all touch events are ignored further down the line, so that, for example, the scrollviewer doesn't start scrolling.
When OnPreviewTouchDown is called, I set the boolean to true so that events don't propagate. I also start a timer for the touch and hold part. In the mean time, I monitor how far the finger moves on the screen. If it moves far enough, I assume the user wants to scroll, so I stop doing anything and let WPF handle everything as it wants. If the finger doesn't move farther than the set limit before the timer fires, I assume that this is actually a touch and hold event. At this point I perform the following actions:
Execute the TouchedAndHeld command to let whoever is interested know that this event occurred, passing along the relevant information;
Start monitoring the for manipulation events and execute the ManipulationDeltaChanged command, again, to let whoever binds to this command know that manipulation events have occurred and take the appropriate actions. Of note is that I also set e.Handled to true so that the scroll viewer doesn't start scrolling while I move around the control.
And finally, we are ready to actually use this thing. I therefore have a scrollviewer with my touch and hold control:
<ScrollViewer Style="{StaticResource MyScrollViewer}">
<ItemsControl ItemsSource="{Binding SomeButtons}" x:Name="SomeButtonsRoot">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Style="{StaticResource SomeButtonsWrapPanel}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:SomeButton Icon="{Binding Icon}" Text="{Binding Name}"
SelectCmd="{Binding ButtonSelectedCmd}" SelectCmdParam="{Binding SomeParam}"
TouchedAndHeld="{Binding DataContext.SomeButtonDragStartedCmd, ElementName=SomeButtonsRoot}"
ManipulationDeltaChanged="{Binding DataContext.SomeButtonDraggingCmd, ElementName=SomeButtonsRoot}">
<controls:SomeButton.TouchedAndHeldParam>
<MultiBinding Converter="{StaticResource List}">
<Binding />
<Binding RelativeSource="{RelativeSource Self}"/>
<Binding ElementName="CanvasRoot"/>
</MultiBinding>
</controls:SomeButton.TouchedAndHeldParam>
</controls:SomeButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
The scrollviewer is placed inside a Canvas. Inside the same Canvas I then have another control:
<controls:SomeButton Icon="{Binding Icon}" Text="{Binding Name}" Panel.ZIndex="100"
Canvas.Left="{Binding InitialPosition.X}" Canvas.Top="{Binding InitialPosition.Y}"
ManipulationDelta="{Binding Translation}"/>
This is the control that will actually be dragged around. The controls in the scroll viewer initiate the touch and hold dragging and then I pass all the manipulation data from the initiating control to this control. The reason I am not dragging the control that started the process, is because scroll viewer, according to this and other answers on stack overflow, will always clip to bounds. So, instead of messing with margins, paddings and Z indices, I just place a proxy control in the canvas that I can move wherever I want and I know it will be visible.
The code so far is promising. When I touch and hold the control in the scroll viewer, another control pops up righ above it and when I move my finger, that control perfectly reflects my gestures but only on the Y axis. Why is that?
I decided to see what the ScrollViewer is actually doing, so I searched for the source code. Fortunately, I found the code right here.
Starting with line 1645, inside the OnManipulationStarting override, the code checks what panning mode was set for the ScrollViewer and, based on the value, it changes the ManipulationModes of the ManipulationStartingEventArgs. For PanningMode.VerticalOnly, the mode is set to ManipulationModes.TranslateY. Aha! That's why I was only getting the Y values.
To fix this "feature", I simply extended the ScrollViewer class and overriden the same OnManipulationStarting and made sure that manipulation mode remains unchanged:
public class TouchScrollViewer : ScrollViewer
{
protected override void OnManipulationStarting(ManipulationStartingEventArgs e)
{
var initialMode = e.Mode; // Keep note of the original manipulation mode.
base.OnManipulationStarting(e); // Let the ScrollViewer do it's thing.
e.Mode = initialMode; // Ensure the original manipulation mode is used.
}
}
Thankfully, OnManipulationStarting is actually part of the UIElement class, which the ScrollViewer ultimately extends, and is marked as protected, so we can override it in our extension class as we see fit.
I switched to using TouchScrollViewer in XAML instead of the original ScrollViewer, and now everything works as expected.
I won't mark this as the definitive answer for now, just in case someone offers a better solution.
In case the link goes down or the code on the page changes, here are the relevant bits:
protected override void OnManipulationStarting(ManipulationStartingEventArgs e)
{
...
PanningMode panningMode = PanningMode;
if (panningMode != PanningMode.None)
{
...
if (ShouldManipulateScroll(e, viewport))
{
// Set Manipulation mode and container
if (panningMode == PanningMode.HorizontalOnly)
{
e.Mode = ManipulationModes.TranslateX;
}
else if (panningMode == PanningMode.VerticalOnly)
{
e.Mode = ManipulationModes.TranslateY;
}
else
{
e.Mode = ManipulationModes.Translate;
}
...
}
...
}
}
I have created two separate usercontrols, they are meant to work together.
The first one is a simple usercontrol with a thumb attached to it, the thumb makes the control move around by dragging, this is simple and working.
XAML:
<Canvas>
<Thumb x:Name="Thumb" Width="15" Height="15" DragDelta="Thumb_DragDelta"/>
</Canvas>
Code-Behind: A dependency property called Position, when Setter is called it updates the usercontrol's margin.
public partial class ThumbPoint : UserControl
{
public Point Position
{
get { return (Point)GetValue(PositionProperty); }
set { SetValue(PositionProperty, value); this.Margin = new Thickness(value.X, value.Y, 0, 0); }
}
// Using a DependencyProperty as the backing store for Position. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PositionProperty =
DependencyProperty.Register("Position", typeof(Point), typeof(ThumbPoint), new PropertyMetadata(new Point()));
public ThumbPoint()
{
InitializeComponent();
Position = new Point(0, 0);
}
private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
Position = new Point(Position.X + e.HorizontalChange, Position.Y + e.VerticalChange);
}
}
The second UserControl is called StraightLine, its composed of a Line control
XAML:
<Canvas>
<Line x:Name="Line" Stroke="Gray" StrokeThickness="1"/>
</Canvas>
Code-Behind: A dependency property called StartPosition, when Setter is called it updates the Line X1 and Y1 (starting position of the line).
public partial class StraightLine : UserControl
{
public Point StartPosition
{
get { return (Point)GetValue(StartPositionProperty); }
set { SetValue(StartPositionProperty, value); Line.X1 = value.X; Line.Y1 = value.Y; }
}
// Using a DependencyProperty as the backing store for StartPosition. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StartPositionProperty =
DependencyProperty.Register("StartPosition", typeof(Point), typeof(StraightLine), new PropertyMetadata(new Point()));
public StraightLine()
{
InitializeComponent();
Line.X1 = 0;
Line.Y1 = 0;
Line.X2 = 300;
Line.Y2 = 200;
}
}
Here I am trying to bind them together on the mainwindow.xaml:
<Canvas>
<local:ThumbPoint x:Name="ThumbPoint"/>
<local:StraightLine StartPosition="{Binding Position, ElementName=ThumbPoint}"/>
</Canvas>
Desired effect: DependencyProperty StartPosition of the StraightLine should be updated.
Whats happening: It's not being updated so only the ThumbPoint is moving.
binding doesn't use common property wrappers for DP (public Point StartPosition), it uses SetValue() directly, so code in setter isn't invoked.
What is needed is propertyChangedCallback:
public Point StartPosition
{
get { return (Point)GetValue(StartPositionProperty); }
set { SetValue(StartPositionProperty, value); }
}
public static readonly DependencyProperty StartPositionProperty =
DependencyProperty.Register("StartPosition", typeof(Point), typeof(StraightLine), new PropertyMetadata(new Point(), OnStartPositionChanged));
private static void OnStartPositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
StraightLine c = (StraightLine) d;
c.Line.X1 = c.StartPosition.X;
c.Line.Y1 = c.StartPosition.Y;
}
in ThumbPoint public Point Position property has the same issue but it works there because you use setter directly: Position = new Point()
Alternatively bind X1 and Y1 value in xaml:
<Canvas>
<Line x:Name="Line" Stroke="Gray" StrokeThickness="1"
X1="{Binding StartPosition.X, RelativeSource={RelativeSource AncestorType=StraightLine}}"
Y1="{Binding StartPosition.Y, RelativeSource={RelativeSource AncestorType=StraightLine}}"/>
</Canvas>
(or use ElementName instead of RelativeSource)
I am rebuilding in wpf my vb6 application that is working perfectly since 2011.
My app handles 11 documents. In vb6 I used 11 forms in an MDI.
In wpf I am using a Canvas that I called Hold. This canvas holds 11 instances of a FrameworkElement that I called Doc.
Doc has methods for drawing shape and text for a class that I called Cell.
In order to place cells in Doc, In need Doc to draw a grid. For that I have a Boolean field (bool _showGrid;) if true Doc draws the grid.
My problem is that Doc FrameworkElement does not draw the grid when called from xaml. But from Window_Loaded it does.
this is a part of the Doc FrameworkElement:
public class Doc : FrameworkElement
{
VisualCollection paper;
DrawingVisual cellMaker;
bool _showGrid;
public Doc()
{
paper = new VisualCollection(this);
//SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
}
public bool showGrid
{
set
{
_showGrid = value;
if (_showGrid)
{
drawGrid();
}
}
}
private void drawGrid()
{
DrawingVisual grid = new DrawingVisual();
using(DrawingContext dc = grid.RenderOpen())
{
for(int i = 0; i <= Width; i += 18)
{
dc.DrawLine(new Pen(Brushes.OrangeRed, 1), new Point(i, 0), new Point(i, Height));
}
for(int j = 0; j <= Height; j += 18)
{
dc.DrawLine(new Pen(Brushes.OrangeRed, 1), new Point(0, j), new Point(Width, j));
}
dc.Close();
}
paper.Add(grid);
}
And this is xaml where documentsReceipt instance of Doc is created in showGrid is set to true witch is not working:
<ScrollViewer Grid.Row="1" Grid.Column="0">
<Canvas Name="Hold" Width="21cm" Height="29.7cm" Background="White" Margin="17">
<dc:Doc Name="documentsReceipt"
Width="{Binding Path=ActualWidth,ElementName=Hold}"
Height="{Binding Path=ActualHeight,ElementName=Hold}"
showGrid="True"
Loaded="documentsReceipt_Loaded">
</dc:Doc>
<TextBox Name="txt"
TextChanged="txt_TextChanged"
KeyDown="txt_KeyDown"
PreviewKeyDown="txt_PreviewKeyDown"/>
</Canvas>
</ScrollViewer>
This is the app with when I omit documentReceipt=true from Window_Loaded
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//documentsReceipt.showGrid = true;
}
Window without grid
And this is the output when I enable showGrid
Window with grid
Usually you implement a control like this a little bit different. First of all you need a dependency property for ShowGrid to be bindable. Next is you override OnRender to draw your shapes (or what ever). Here is the full implementation of the control:
public class Doc : FrameworkElement
{
public bool ShowGrid
{
get { return (bool)GetValue (ShowGridProperty); }
set { SetValue (ShowGridProperty, value); }
}
public static readonly DependencyProperty ShowGridProperty =
DependencyProperty.Register ("ShowGrid", typeof (bool), typeof (Doc), new FrameworkPropertyMetadata (false, FrameworkPropertyMetadataOptions.AffectsRender));
protected override void OnRender (DrawingContext dc)
{
if (ShowGrid)
{
for (int i = 0; i <= ActualWidth; i += 18)
{
dc.DrawLine (new Pen (Brushes.OrangeRed, 1), new Point (i, 0), new Point (i, Height));
}
for (int j = 0; j <= ActualHeight; j += 18)
{
dc.DrawLine (new Pen (Brushes.OrangeRed, 1), new Point (0, j), new Point (Width, j));
}
}
}
}
I am having some troubles with my datagrid ( WPF ) and since I am already a beginner I am not so very good in it.
Maybe, someone can help me out here.
I already have the row-index and column index and what I want to have now is the value from this cell.
But I do not know how to get it.
Here is my code:
var row = datagrid.Items.IndexOf(datagrid.CurrentItem);
var column = datagrid.SelectedCells[0].Column.DisplayIndex;
How is it possible now to retrieve with these two indexes now my cell vlaue.
I must solve it somehow via the indexes!
Thank you very much for your help!
Here is the sample code that gets cell value from datagrid in WPF on button click
In your MainWindow.cs
private ObservableCollection<ItemDG> _it = new ObservableCollection<ItemDG>();
public MainWindow()
{
InitializeComponent();
_it.Add(new ItemDG() { Amount = 10 });
_it.Add(new ItemDG() { Amount = 20 });
_it.Add(new ItemDG() { Amount = 30 });
dataGrid1.ItemsSource = _it;
}
private void button1_Click_1(object sender, RoutedEventArgs e)
{
TextBlock x = dataGrid1.Columns[0].GetCellContent(dataGrid1.Items[2]) as TextBlock;
if (x != null)
MessageBox.Show(x.Text);
}
}
public class ItemDG
{
public int Amount { get; set; }
}
and in your MainWindow.xaml
<DataGrid AutoGenerateColumns="False" Name="datagrid1"/>
<Button Content="Button" Name="button1" Click="button1_Click_1" />