WPF GridSplitter видимость
У меня проблема с видимостью GridSplitter.
В этом, что бы я ни размещал, Winform DataGridView. При перетаскивании GridSplitter правильно отображается на других элементах управления. Но не в этой сетке. Фактически, все, что я размещаю вместо Datagridview, становится верхним элементом управления, что заставляет GridSplitter скрываться за ним.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Name="rowForButton"/>
<RowDefinition Name="rowForGridSplitter" Height="Auto" MinHeight="81" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Height="50" Width="110" Content="Button in First Row"/>
<my:WindowsFormsHost Panel.ZIndex="0" Grid.Row="1" Margin="30,11,138,0" x:Name="winHost" Height="58" VerticalAlignment="Top" OpacityMask="Transparent">
<win:DataGridView x:Name="dataGridView"></win:DataGridView>
</my:WindowsFormsHost>
<GridSplitter BorderThickness="1" Panel.ZIndex="1" Grid.Row="1" HorizontalAlignment="Stretch" Height="5" ShowsPreview="True" VerticalAlignment="Top">
</GridSplitter>
</Grid>
6 ответов
Элементы управления Windows Forms всегда отображаются отдельно от элементов управления WPF и, как результат, всегда будут отображаться над приложением WPF.
Посмотрите Хостинг окна Microsoft Win32 в WPF (подзаголовок Существенные различия в поведении вывода) для получения дополнительной информации.
Я столкнулся с этой проблемой также, есть мое решение:
var splitter = new GridSplitter()
{
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
FocusVisualStyle = null,
ShowsPreview = true,
Background = new SolidColorBrush(new Color() { R = 1, G = 1, B = 1, A = 1 }),
};
// non-style / essential window which will display over your WinForm control
var PopupWindowForSplitter = new PopupWindow()
{
Background = new SolidColorBrush(new Color() { R = 1, G = 1, B = 1, A = 1 }),
Visibility = Visibility.Collapsed
};
PopupWindowForSplitter.Show();
...
Point _ptForSplitterDrag = new Point(0,0);
splitter.DragStarted += (o, e) =>
{
var pt = splitter.PointToScreen(new Point());
_ptForSplitterDrag = splitter.PointToScreen(Mouse.GetPosition(splitter));
PopupWindowForSplitter.Left = pt.X;
PopupWindowForSplitter.Top = pt.Y;
PopupWindowForSplitter.Height = splitter.ActualHeight;
PopupWindowForSplitter.Width = splitter.ActualWidth;
PopupWindowForSplitter.Activate();
PopupWindowForSplitter.Visibility = Visibility.Visible;
};
splitter.DragDelta += (o, e) =>
{
var pt = splitter.PointToScreen(Mouse.GetPosition(splitter)) - _ptForSplitterDrag
+ splitter.PointToScreen(new Point());
if (splitter.ResizeDirection == GridResizeDirection.Rows)
{
PopupWindowForSplitter.Top = pt.Y;
}
else
{
PopupWindowForSplitter.Left = pt.X;
}
};
splitter.DragCompleted += (o, e) =>
{
var initializeData = typeof(GridSplitter).GetMethod("InitializeData", BindingFlags.NonPublic | BindingFlags.Instance);
var moveSplitter = typeof(GridSplitter).GetMethod("MoveSplitter", BindingFlags.NonPublic | BindingFlags.Instance);
if (moveSplitter != null && initializeData != null)
{
initializeData.Invoke(splitter, new object[] { true });
var pt = splitter.PointToScreen(Mouse.GetPosition(splitter)) - _ptForSplitterDrag;
if (splitter.ResizeDirection == GridResizeDirection.Rows)
{
moveSplitter.Invoke(splitter, new object[] { 0, pt.Y });
}
else
{
moveSplitter.Invoke(splitter, new object[] { pt.X, 0 });
}
}
PopupWindowForSplitter.Visibility = Visibility.Collapsed;
};
Может быть, в моем описании есть некоторые проблемы из-за моего плохого английского, но я думаю, что кода достаточно, чтобы объяснить это.
Обычно вы должны либо поместить GridSplitter в его собственную ячейку сетки, либо убедиться через поля, что ни один элемент управления не может перекрывать его. Но я не знаю, относится ли это именно к вам здесь. Смотрите также здесь.
В вашей ситуации самым быстрым решением было бы переместить GirdSplitter в строку с помощью кнопки:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Name="rowForButton"/>
<RowDefinition Name="rowForGridSplitter" Height="Auto" MinHeight="81" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Height="50" Width="110" Content="Button in First Row"/>
<my:WindowsFormsHost Panel.ZIndex="0" Grid.Row="1" Margin="30,11,138,0" x:Name="winHost" Height="58" VerticalAlignment="Top" OpacityMask="Transparent">
<win:DataGridView x:Name="dataGridView"></win:DataGridView>
</my:WindowsFormsHost>
<GridSplitter BorderThickness="1" Panel.ZIndex="1" Grid.Row="0" HorizontalAlignment="Stretch" Height="5" ShowsPreview="True" VerticalAlignment="Bottom">
</GridSplitter>
</Grid>
Теперь просто отрегулируйте поля, чтобы убедиться, что между кнопкой и разделителем сетки есть свободное пространство.
Попробуйте использовать WPF-собственный элемент управления DataGrid. Есть несколько коммерческих сторонних элементов управления, которые вы можете купить, или вы можете взглянуть на один из предоставленных Microsoft (в настоящее время все еще в CTP):
Решением было бы добавить метку "Форма Windows" внутри разделителя сетки и сделать это программно после добавления DataGridView, чтобы он отображался поверх него, следующим образом:
void AddLabelToSplitter()
{
string template =
@" <ControlTemplate
xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:mn='clr-namespace:MyNameSpace;assembly=MyAssembly'
xmlns:wf='clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' TargetType='{x:Type GridSplitter}'>
<mn:ExtendedWindowsFormsHost x:Name='Grid_Splitter_WindowsFormsHost' HorizontalAlignment='Stretch' VerticalAlignment='Stretch'>
<wf:Label Dock='Fill' BackColor='DarkGray'></wf:Label>
</mn:ExtendedWindowsFormsHost>
</ControlTemplate>";
Grid_Splitter.Template = (ControlTemplate)XamlReader.Parse(template);
}
Использование обычного хоста формы Windows не будет работать, так как он не будет передавать события мыши в сплиттер, поэтому вместо этого используйте ссылку ExtendedWindowsFormsHost из ссылки ниже: