I am trying to create a UserControl that behaves like so:
A button to start with, and when a user clicks it and holds, a Radial menu appears
User keeps holding left mouse, and releases on the menu item they want
I am using this Radial menu https://github.com/Julien-Marcou/RadialMenu
Here is my attempt:
<UserControl x:Class="NetBoard.RadialButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:NetBoard"
xmlns:radial="clr-namespace:RadialMenu.Controls;assembly=RadialMenu"
mc:Ignorable="d" >
<Grid>
<Button Name="Button"
PreviewMouseDown="Button_MouseDown"
PreviewMouseUp="Button_MouseUp" />
<radial:RadialMenu Name="RadialMenu" />
</Grid>
</UserControl>
public partial class RadialButton : UserControl
{
public RadialButton()
{
InitializeComponent();
// Test menu items
for (int i = 0; i < 3; i++)
{
RadialMenu.Content.Add(new RadialMenuItem { Content = i });
}
foreach (RadialMenuItem item in RadialMenu.Content)
{
item.PreviewMouseLeftButtonUp += Slice_MouseUp;
}
}
private void Button_MouseDown(object sender, MouseButtonEventArgs e)
{
RadialMenu.IsOpen = true;
}
private void Button_MouseUp(object sender, MouseButtonEventArgs e)
{
RadialMenu.IsOpen = false;
}
private void Slice_MouseUp(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("It worked!");
}
The radial menu pops up fine, but the PreviewMouseLeftButtonUp event does not fire on the RadialMenuItems. The Menu Items don't even behave like they are being moused-over (they would change color).
Any ideas on how to accomplish this?
I actually got this working using a Label instead of a button.
Related
I have situation where I want an overlay control to block UI interactions on a Page for everything that is behind a border. I have tried setting Border.ManipulationMode to False. I have set IsTapEnabled, IsRightTapEnabled, IsDoubleTapEnabled, and IsHitTestVisible to False.
I also tried subscribing to the Tapped and PointerEntered events, and setting the args Handled property to true. After all of this I can still click on Buttons through the border, and invoke their commands. Below are a few screenshots for context:
Page with no overlay
Page now has what should be an overlay that blocks controls behind it
A button capturing PointerOver that shouldn't be
Here is the UserControl xaml that becomes the overaly on the Page:
<UserControl x:Class="PocMvvmToolkitApp.Dialogs.DialogShell"
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"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid x:Name="overlayGrid"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<!--dialogShield is the Border that I want to prevent click through on-->
<Border x:Name="dialogShield"
Background="#AAFFFFFF"
IsHitTestVisible="False"
ManipulationMode="None"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
IsDoubleTapEnabled="False"
IsHoldingEnabled="False"
IsRightTapEnabled="False"
IsTapEnabled="False"/>
<Border x:Name="dialogBorder"
BorderBrush="Black"
BorderThickness="1" />
</Grid>
Attempting to handle the events:
public DialogShell()
{
this.InitializeComponent();
this.allDialogs = new List<ExtendedContentDialog>();
this.visibleDialogs = new List<ExtendedContentDialog>();
////Doesn't work
this.dialogShield.PointerEntered += this.OnModalShieldPointerEntered;
this.dialogShield.Tapped += this.OnModalShieldTapped;
}
private void OnModalShieldTapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
////Doesn't block click through
e.Handled = true;
}
private void OnModalShieldPointerEntered(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
e.Handled = true;
}
On the Page.xaml.cs here is where I add or remove the DialogShell control to the parent Grid on the page:
private void OnDialogStackChanged(Args.DialogStackChangedEventArgs args)
{
switch (args.Context)
{
case Args.DialogStackChangedContext.Showing:
if (this.dialogShell == null)
{
this.dialogShell = new DialogShell();
this.dialogShell.ShowDialog(args.Dialog);
this.rootGrid.Children.Add(this.dialogShell);
Grid.SetColumnSpan(this.dialogShell, 2);
}
break;
case Args.DialogStackChangedContext.Closing:
if (this.dialogShell != null)
{
this.dialogShell.RemoveDialog(args.Dialog);
if (this.dialogShell.AllDialogs.Count == 0)
{
this.rootGrid.Children.Remove(this.dialogShell);
this.dialogShell = null;
}
}
break;
}
}
Any help with this Border situation would be appreciated. Before someone recommends using ContentDialog, please don't, I have my reasons for this setup. Thanks!
I have a piece of code with two Border elements, but the hit-testing only works for the topmost Border (Border2) in the code below. This means that when I right-click, I see the message box, but when I left-click, nothing happens. Is there a way to fix this so that I can capture different mouse events with sibling controls that have different Z-index values? Here is my code:
<Window x:Class="HiTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HiTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:Border1 Background="Transparent"/>
<local:Border2 Background="Transparent"/>
</Grid>
</Window>
public class Border1 : Border
{
public Border1()
{
MouseLeftButtonDown += Border1_MouseLeftButtonDown;
}
private void Border1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Left");
}
}
public class Border2 : Border
{
public Border2()
{
MouseRightButtonDown += Border2_MouseRightButtonDown;
}
private void Border2_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Right");
}
}
In summary, I want to be able to capture different mouse events with sibling controls that have different Z-index values. How can I achieve this?
it is not possible to capture events for sibling elements. Bubbling only works for elements with parent and child relation.
Something like this with parent child relation.
<Grid Name="Parent">
<Border Name="Border01" Background="Transparent" MouseDown="Border01_MouseDown">
<Border Name="Border02" Background="Transparent" MouseDown="Border01_MouseDown" />
</Border>
</Grid>
private void Border01_MouseDown(object sender, MouseButtonEventArgs e)
{
if (sender.GetType() == typeof(Grid)) { }
if (sender.GetType() == typeof(Border))
{
if (((Border)sender).Name == "Border01" & e.LeftButton == MouseButtonState.Pressed)
{
MessageBox.Show("Left & Button01");
}
if (((Border)sender).Name == "Border02" & e.RightButton == MouseButtonState.Pressed)
{
MessageBox.Show("Right & Button02");
}
}
}
If you have sibling elements you need to delegate the MouseDown from the top element to the lower element by yourself.
Currently users can draw on the canvas by clicking and dragging their mouse. How can I change the color of the line to indicate the user's cursor is hovering over the line? It would be ideal to make it highlight when the cursor is within 5 pixels of any given line to indicate they are close.
Inital drawing...
When user's cursor is either hovering directly over or within 5 pixels of any given line.
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Canvas Name="paintSurface" MouseDown="Canvas_MouseDown_1" MouseMove="Canvas_MouseMove_1" >
<Canvas.Background>
<SolidColorBrush Color="White" Opacity="0"/>
</Canvas.Background>
</Canvas>
</Grid>
</Window>
MainWindow.cs
using System.Windows;
using System.Windows.Input;
using System.Windows.Shapes;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Point currentPoint = new Point();
public MainWindow()
{
InitializeComponent();
}
private void Canvas_MouseDown_1(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (e.ButtonState == MouseButtonState.Pressed)
currentPoint = e.GetPosition(this);
}
private void Canvas_MouseMove_1(object sender, System.Windows.Input.MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Line line = new Line();
line.Stroke = SystemColors.WindowFrameBrush;
line.X1 = currentPoint.X;
line.Y1 = currentPoint.Y;
line.X2 = e.GetPosition(this).X;
line.Y2 = e.GetPosition(this).Y;
currentPoint = e.GetPosition(this);
paintSurface.Children.Add(line);
}
}
}
}
Note: There are two versions of the sample program here, new and old. Take a look at both to get an idea of what you can do.
Here's a sample application that fixes the issue you were unaware of, which is the fact that you drew numerous lines with one stroke and not a single line. You should use a Polyline. If you use Visual Studio 2015, then there's a Live Visual Tree, which will show you exactly what I mean; otherwise, you can use a tool such as Snoop to see the same thing. It also addresses you original question, which is the highlighting.
The new version is the first code portion that is shown here. It uses a dictionary to link base line and highlight lines, so that you may get to the underlying base line if need to (such as when you want to delete it). It also highlights the base, versus the highlighting the highlight line, which is what the old version did. The highlight line is simply used for the selection zone buffer. Increase or decrease its stroke to get the desired selection buffer (you mentioned 5 pixels in your post).
Preview:
XAML:
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Canvas Name="paintSurface" Background="White" MouseDown="Canvas_MouseDown"
MouseUp="Canvas_MouseUp" MouseMove="Canvas_MouseMove"/>
</Window>
C#:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
namespace WpfApplication
{
public partial class MainWindow : Window
{
Polyline _baseLine;
Polyline _highlightLine;
Point _currentPoint;
bool _newLine;
Dictionary<Polyline, Polyline> _lines = new Dictionary<Polyline, Polyline>();
public MainWindow()
{
InitializeComponent();
}
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
_newLine = true;
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
if (_highlightLine != null && !_newline)
{
_highlightLine.MouseEnter += ShowHighlight;
_highlightLine.MouseLeave += HideHighlight;
}
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
if (_newLine)
{
_baseLine = new Polyline
{
Stroke = SystemColors.WindowFrameBrush,
StrokeThickness = 1.0
};
_highlightLine = new Polyline
{
Opacity = 0.0,
Stroke = SystemColors.WindowFrameBrush,
StrokeThickness = 10.0
};
paintSurface.Children.Add(_baseLine);
paintSurface.Children.Add(_highlightLine);
_lines.Add(_highlightLine, _baseLine);
_newLine = false;
}
_currentPoint = e.GetPosition(this);
_baseLine.Points.Add(_currentPoint);
_highlightLine.Points.Add(_currentPoint);
}
}
private void ShowHighlight(object sender, MouseEventArgs e)
{
var line = sender as Polyline;
if (line != null)
{
_lines[line].Stroke = new SolidColorBrush(Colors.LimeGreen);
}
}
private void HideHighlight(object sender, MouseEventArgs e)
{
var line = sender as Polyline;
if (line != null)
{
_lines[line].Stroke = SystemColors.WindowFrameBrush;
}
}
}
}
You'll notice the _newLine flag boolean. I use it to indicate whether a new Polyline should be drawn. When the mouse is down, that's an indicator that a new line needs to be created. I don't hook up the MouseEnter and MouseLeave handles for the line until the mouse is up because I don't want highlighting to be distracting during the drawing process of the line. You have to give some sort of stroke to the _highlightLine and then set its opacity to 0 to make it invisible, but still respond to hit tests; otherwise, MouseEnter and MouseLeave handlers will never get invoked.
OLD (The old version of the program. Still a good one to check out.):
What I do here is add a highlighting polyline on top of the base one and set its stroke to be 10 instead of the base's 1. You can adjust that stroke thickness to get yourself the desired selection "buffer" zone. I literally spent about 10-15 minutes on this, so there could be ways to improve it, but this should give you a solid base to build upon. If you wish to perform some actions down the road on these lines you're highlighting, such being able to delete them, then I suggest adding both the _baseLine and the _highlightLine to a dictionary, where _highlightLine is the key and _baseLine is the value. That way, when you select the _highlightLine, you may access the underlying _baseLine.
Preview:
XAML:
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Canvas Name="paintSurface" Background="White" MouseDown="Canvas_MouseDown"
MouseUp="Canvas_MouseUp" MouseMove="Canvas_MouseMove"/>
</Window>
C#:
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
namespace WpfApplication
{
public partial class MainWindow : Window
{
Polyline _baseLine;
Polyline _highlightLine;
Point _currentPoint;
bool _newLine;
public MainWindow()
{
InitializeComponent();
}
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
_newLine = true;
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
if (_highlightLine != null && !_newline)
{
_highlightLine.MouseEnter += ShowHighlight;
_highlightLine.MouseLeave += HideHighlight;
}
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
if (_newLine)
{
_baseLine = new Polyline
{
Stroke = SystemColors.WindowFrameBrush,
StrokeThickness = 1.0
};
_highlightLine = new Polyline
{
Stroke = new SolidColorBrush(Colors.Green),
Opacity = 0.0,
StrokeThickness = 10.0
};
paintSurface.Children.Add(_baseLine);
paintSurface.Children.Add(_highlightLine);
_newLine = false;
}
_currentPoint = e.GetPosition(this);
_baseLine.Points.Add(_currentPoint);
_highlightLine.Points.Add(_currentPoint);
}
}
private void ShowHighlight(object sender, MouseEventArgs e)
{
var line = sender as Polyline;
if (line != null)
{
line.Opacity = 1.0;
}
}
private void HideHighlight(object sender, MouseEventArgs e)
{
var line = sender as Polyline;
if (line != null)
{
line.Opacity = 0.0;
}
}
}
}
Additional Thoughts:
If you want to go full XAML as far as styling, you've got a few options. First option is to create a style that highlights TargetType Polyline on IsMouseOver property being true; however, you won't get the 5 pixel buffer with this one. To accomplish that 5 pixel buffer, you'd need to create a custom template, which requires more work than what I've demonstrated here. Of course... if you're feeling very adventurous, there's always the option of deriving from Shape and create yourself a highlightable/selectable Polyline -- it's just a lot of work, compared to the above code. The bright side is that it'll be reusable. It just depends on your situation, needs and wants.
I created 2 button in WPF window and also added mouse down and mouse up event for both buttons. I did mouse down on one button and mouse up on second. but i am getting same first button object to event handler in both events. My question is why i am not getting the second button object in mouse up event.
This is my XAML
<Window x:Class="MouseDownUpSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button x:Name="but1" Content="source" HorizontalAlignment="Left" Margin="86,68,0,0" VerticalAlignment="Top" Width="75" PreviewMouseLeftButtonDown="Button_MouseDown" PreviewMouseLeftButtonUp="Button_MouseUp" />
<Button x:Name="but2" Content="destination" HorizontalAlignment="Left" Margin="406,164,0,0" VerticalAlignment="Top" Width="75" PreviewMouseLeftButtonDown="Button_MouseDown" PreviewMouseLeftButtonUp="Button_MouseUp"/>
</Grid>
Code
public partial class MainWindow : Window
{
string source = null;
string destination = null;
public MainWindow()
{
InitializeComponent();
}
private void Button_MouseDown(object sender, MouseButtonEventArgs e)
{
Button src=sender as Button;
source = src.Content as string;
}
private void Button_MouseUp(object sender, MouseButtonEventArgs e)
{
Button src = sender as Button;
destination = src.Content as string;
if(destination.Equals(source))
{
}
}
I am trying to transfer data from one object to another through drag & drop
My question is why i am not getting the second button object in mouse up event.
Because this is how buttons work.
Taken from MSDN:
If a mouse button is pressed while the pointer is over a form or control, that object "captures" the mouse and receives all mouse events up to and including the last MouseUp event.
This might also interest you:
If mouse buttons are pressed in succession, the object that captures the mouse after the first press receives all mouse events until all buttons are released.
Mouse.MouseDown occurs when any mouse button is pressed, where as Mouse.MouseUp occurs when any mouse button is released. So when you click a button MouseUp event is always followed by MouseDown event since they are sequential events. Hence your if() condition is always true in this case.
if(destination.Equals(source))
{
//always executed;
}
I achieved my goal through WPF drag & drop using DragDropEffects.Copy
XAML
<Window x:Class="MouseDownUpSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button x:Name="but1" Content="source" HorizontalAlignment="Left" Margin="86,68,0,0" VerticalAlignment="Top"
Width="75" PreviewMouseMove="but_MouseMove" AllowDrop="True" PreviewDrop="but_Drop" />
<Button x:Name="but2" Content="destination" HorizontalAlignment="Left" Margin="406,164,0,0" VerticalAlignment="Top"
Width="75" PreviewMouseMove="but_MouseMove" AllowDrop="True" PreviewDrop="but_Drop"/>
</Grid>
CODE
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void but_MouseMove(object sender, MouseEventArgs e)
{
Button src=sender as Button;
if (src != null && e.LeftButton == MouseButtonState.Pressed)
{
DragDrop.DoDragDrop(src,
src.Content.ToString(),
DragDropEffects.Copy);
}
}
private void but_Drop(object sender, DragEventArgs e)
{
Button dest = sender as Button;
string destinationContent = null;
destinationContent = dest.Content as string;
if (dest != null)
{
if (e.Data.GetDataPresent(DataFormats.StringFormat))
{
string sourceContent = (string)e.Data.GetData(DataFormats.StringFormat);
if (destinationContent.Equals(sourceContent))
{
Console.WriteLine("equal");
}
}
}
}
}
In WinForm DataGridView, it automatically selects the first row when initialized. It drove me crazy when I tried to turn that feature off. Moving to WPF DataGrid, it seems Microsoft has decided to turn this feature off, which is a good thing I think. However, I have hard time to enable this feature now. For some DataGrid, I want the first row to be selected automatically after grid is populated through data binding. There are some suggestions in Internet, but I couldn't make that work. I hope for better luck here.
Set IsSynchronizedWithCurrentItem = "true".
EDIT:
To address your comment, I assume that your DataGrid's SelectionUnit is set to "Cell", is it? Okay, I'm not sure if this is the best solution but one thing you can do is handle the Loaded event for the DataGrid and manually set the selected cell in the code-behind. So you'll have something like this:
<DataGrid x:Name="dg" AutoGenerateColumns="False" IsSynchronizedWithCurrentItem="True"
SelectedCellsChanged="dg_SelectedCellsChanged" SelectionUnit="Cell"
Loaded="dg_Loaded">
...
</DataGrid>
Event-Handler:
private void dg_Loaded(object sender, RoutedEventArgs e)
{
if ((dg.Items.Count > 0) &&
(dg.Columns.Count > 0))
{
//Select the first column of the first item.
dg.CurrentCell = new DataGridCellInfo(dg.Items[0], dg.Columns[0]);
dg.SelectedCells.Add(dg.CurrentCell);
}
}
Note that this will only work if the DataGrid.SelectionUnit is set to "Cell". Otherwise, I believe it will throw an exception.
EDIT2:
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" Height="350" Width="525">
<StackPanel>
<Button Click="Button_Click">Reset</Button>
<DataGrid x:Name="dg" AutoGenerateColumns="False" IsSynchronizedWithCurrentItem="True"
SelectionUnit="Cell"
DataContextChanged="dg_DataContextChanged"
ItemsSource="{Binding Items}"
Loaded="dg_Loaded">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding}"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Window>
Code-Behind:
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.LoadItems();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.LoadItems();
}
private void LoadItems()
{
this.DataContext = new { Items = new List<string> { "Item1", "Item2", "Item3" } };
this.SelectFirstItem();
}
private void dg_Loaded(object sender, RoutedEventArgs e)
{
SelectFirstItem();
}
void SelectFirstItem()
{
if ((dg.Items.Count > 0) &&
(dg.Columns.Count > 0))
{
//Select the first column of the first item.
dg.CurrentCell = new DataGridCellInfo(dg.Items[0], dg.Columns[0]);
dg.SelectedCells.Add(dg.CurrentCell);
}
}
private void dg_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
this.SelectFirstItem();
}
}
}
You can do this consistently in the DataGrid.Loaded event. Just obtain the first row and have the row fire the selection event.
void MyGridLoaded(...) {
DataGridRow r = yourGrid.ItemContainergenerator.ContainerFromIndex(0) as DataGridRow;
if(r != null) {
r.IsSelected = false;
r.IsSelected = true;
}
}
I'm not sure this is a bug because you may not be guaranteed to have selection events fire from your object until the control is loaded. Don't know.
You could try this.
this.dataGrid.SelectionMode = DataGridSelectionMode.Single;
// Selects the 4th row.
this.dataGrid.SelectedIndex = 3;
I'm glad to report I found a solution for this problem through ItemContainerGenerator.StatusChanged event.
dataGrid.ItemContainerGenerator.StatusChanged += new EventHandler(ItemContainerGenerator_StatusChanged);
void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
if (dataGrid.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
dataGrid.SelectedIndex = 0;
}
}
It looks when this event is fired with status ContainersGenerated, dataGrid is fully initialized. To me, this is more like DataGridView's DataBindingComplete event in WinForm. If so, the "DataContextChanged" event should really be called "DataContextChanging" event.
This was inspired by a post here I accidently found while looking for another clue.