Я хочу переместить логи c из файла xaml.cs для дальнейшего повторного использования в других компонентах представления. Я знаю, что я должен реализовать шаблон mvvm для достижения этой цели. Основная проблема, которую я не могу понять, как избавиться от сильной зависимости с помощью пользовательского интерфейса. Например, код, который я хочу переместить в отдельный класс, зависит от таких элементов пользовательского интерфейса, как CanDrawing canvas, PixelsInMillimeterTextBox text box, Image ReferenceImage. Как сделать что-то подобное? Я хочу вырезать это из MainWindow.Xaml.cs:
private Line _selectedLine;
private List<Line> _horizontalLines = new List<Line>();
private List<Line> _verticalLines = new List<Line>();
private bool _twoLineMode = false;
private List<Line> _lines = new List<Line>();
[DllImport("gdi32.dll")]
private static extern bool LineDDA(int nXStart, int nYStart, int nXEnd, int nYEnd, LineDdaProc lpLineFunc, IntPtr lpData);
// The signature for the callback method
private delegate void LineDdaProc(int x, int y, IntPtr lpData);
// The mouse is up. See whether we're over an end point or segment.
private void canDrawing_MouseMove_NotDown(object sender, MouseEventArgs e)
{
Cursor newCursor = Cursors.Cross;
// See what we're over.
Point location = e.MouseDevice.GetPosition(CanDrawing);
// Set the new cursor.
if (CanDrawing.Cursor != newCursor)
CanDrawing.Cursor = newCursor;
}
// See what we're over and start doing whatever is appropriate.
private void canDrawing_MouseDown(object sender, MouseButtonEventArgs e)
{
// See what we're over.
Point location = e.MouseDevice.GetPosition(CanDrawing);
// Start drawing a new segment.
CanDrawing.MouseMove -= canDrawing_MouseMove_NotDown;
CanDrawing.MouseMove += canDrawing_MouseMove_Drawing;
CanDrawing.MouseUp += canDrawing_MouseUp_Drawing;
CanDrawing.MouseLeave += ReferenceImage_NewSegmentDrawingMouseLeave;
Application.Current.Deactivated += ReferenceImage_NewSegmentDrawingLostFocus;
_selectedLine = new Line
{
Stroke = Brushes.Yellow,
X1 = e.GetPosition(ReferenceImage).X,
Y1 = e.GetPosition(ReferenceImage).Y,
X2 = e.GetPosition(ReferenceImage).X,
Y2 = e.GetPosition(ReferenceImage).Y
};
CanDrawing.Children.Add(_selectedLine);
}
#region Drawing
// We're drawing a new segment.
private void canDrawing_MouseMove_Drawing(object sender, MouseEventArgs e)
{
// Update the new line's end point.
_selectedLine.X2 = e.GetPosition(ReferenceImage).X;
_selectedLine.Y2 = e.GetPosition(ReferenceImage).Y;
}
// Stop drawing.
private void canDrawing_MouseUp_Drawing(object sender, MouseEventArgs e)
{
// Reset the event handlers.
CanDrawing.MouseMove -= canDrawing_MouseMove_Drawing;
CanDrawing.MouseMove += canDrawing_MouseMove_NotDown;
CanDrawing.MouseUp -= canDrawing_MouseUp_Drawing;
CanDrawing.MouseLeave -= ReferenceImage_NewSegmentDrawingMouseLeave;
Application.Current.Deactivated -= ReferenceImage_NewSegmentDrawingLostFocus;
// If the new segment has no length, delete it.
if ((_selectedLine.X1 == _selectedLine.X2) && (_selectedLine.Y1 == _selectedLine.Y2) || _selectedLine == null)
CanDrawing.Children.Remove(_selectedLine);
else
{
var point11 = new System.Drawing.Point(Convert.ToInt32(_selectedLine.X1), Convert.ToInt32(_selectedLine.Y1));
var point22 = new System.Drawing.Point(Convert.ToInt32(_selectedLine.X2), Convert.ToInt32(_selectedLine.Y2));
if (_twoLineMode)
{
if (Math.Abs(_selectedLine.X1 - _selectedLine.X2) > Math.Abs(_selectedLine.Y1 - _selectedLine.Y2))
{
_selectedLine.Stroke = Brushes.DeepPink;
if (_horizontalLines.Count > 0)
{
CanDrawing.Children.Remove(_horizontalLines[_horizontalLines.Count - 1]);
}
_horizontalLines.Add(_selectedLine);
PixelsInMillimeterTextBox.Text = GetPointsOnLine(point11, point22).Count.ToString();
}
else
{
_selectedLine.Stroke = Brushes.Green;
if (_verticalLines.Count > 0)
{
CanDrawing.Children.Remove(_verticalLines[_verticalLines.Count - 1]);
}
_verticalLines.Add(_selectedLine);
PixelsInMillimeterTextBox.Text = GetPointsOnLine(point11, point22).Count.ToString();
}
_lines.Add(_selectedLine);
}
else
{
_selectedLine.Stroke = Brushes.DeepPink;
if (_lines.Count > 0)
{
CanDrawing.Children.Remove(_lines[_lines.Count - 1]);
}
_lines.Add(_selectedLine);
PixelsInMillimeterTextBox.Text = GetPointsOnLine(point11, point22).Count.ToString();
}
}
}
#endregion Drawing
#region "Control Leave Handlers"
private void ReferenceImage_NewSegmentDrawingMouseLeave(object sender, MouseEventArgs e)
{
if (e.RightButton == MouseButtonState.Pressed)
{
canDrawing_MouseUp_Drawing(sender, e);
}
}
private void ReferenceImage_NewSegmentDrawingLostFocus(object sender, EventArgs e)
{
if (Mouse.RightButton == MouseButtonState.Pressed)
{
canDrawing_MouseUp_Drawing(sender, new MouseEventArgs(Mouse.PrimaryDevice, 0));
}
}
#endregion
private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
foreach (var line in _lines)
{
CanDrawing.Children.Remove(line);
}
_lines.Clear();
}
public static List<Point> GetPointsOnLine(System.Drawing.Point point1, System.Drawing.Point point2)
{
var points = new List<Point>();
var handle = GCHandle.Alloc(points);
try
{
LineDDA(point1.X, point1.Y, point2.X, point2.Y, GetPointsOnLineCallback, GCHandle.ToIntPtr(handle));
}
finally
{
handle.Free();
}
return points;
}
private static void GetPointsOnLineCallback(int x, int y, IntPtr lpData)
{
var handle = GCHandle.FromIntPtr(lpData);
var points = (List<Point>)handle.Target;
points.Add(new Point(x, y));
}
У меня есть MainWindow.Xaml.cs:
namespace DDrop
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ObservableCollection<DropPhoto> DropImages = new ObservableCollection<DropPhoto>();
PythonProvider pythonProvider = new PythonProvider();
ExcelOperations excelOperations = new ExcelOperations();
public MainWindow()
{
InitializeComponent();
Photos.ItemsSource = DropImages;
}
...................................................
// The line we're drawing or moving.
private Line _selectedLine;
private List<Line> _horizontalLines = new List<Line>();
private List<Line> _verticalLines = new List<Line>();
private bool _twoLineMode = false;
private List<Line> _lines = new List<Line>();
[DllImport("gdi32.dll")]
private static extern bool LineDDA(int nXStart, int nYStart, int nXEnd, int nYEnd, LineDdaProc lpLineFunc, IntPtr lpData);
// The signature for the callback method
private delegate void LineDdaProc(int x, int y, IntPtr lpData);
// The mouse is up. See whether we're over an end point or segment.
private void canDrawing_MouseMove_NotDown(object sender, MouseEventArgs e)
{
Cursor newCursor = Cursors.Cross;
// See what we're over.
Point location = e.MouseDevice.GetPosition(CanDrawing);
// Set the new cursor.
if (CanDrawing.Cursor != newCursor)
CanDrawing.Cursor = newCursor;
}
// See what we're over and start doing whatever is appropriate.
private void canDrawing_MouseDown(object sender, MouseButtonEventArgs e)
{
// See what we're over.
Point location = e.MouseDevice.GetPosition(CanDrawing);
// Start drawing a new segment.
CanDrawing.MouseMove -= canDrawing_MouseMove_NotDown;
CanDrawing.MouseMove += canDrawing_MouseMove_Drawing;
CanDrawing.MouseUp += canDrawing_MouseUp_Drawing;
CanDrawing.MouseLeave += ReferenceImage_NewSegmentDrawingMouseLeave;
Application.Current.Deactivated += ReferenceImage_NewSegmentDrawingLostFocus;
_selectedLine = new Line
{
Stroke = Brushes.Yellow,
X1 = e.GetPosition(ReferenceImage).X,
Y1 = e.GetPosition(ReferenceImage).Y,
X2 = e.GetPosition(ReferenceImage).X,
Y2 = e.GetPosition(ReferenceImage).Y
};
CanDrawing.Children.Add(_selectedLine);
}
#region Drawing
// We're drawing a new segment.
private void canDrawing_MouseMove_Drawing(object sender, MouseEventArgs e)
{
// Update the new line's end point.
_selectedLine.X2 = e.GetPosition(ReferenceImage).X;
_selectedLine.Y2 = e.GetPosition(ReferenceImage).Y;
}
// Stop drawing.
private void canDrawing_MouseUp_Drawing(object sender, MouseEventArgs e)
{
// Reset the event handlers.
CanDrawing.MouseMove -= canDrawing_MouseMove_Drawing;
CanDrawing.MouseMove += canDrawing_MouseMove_NotDown;
CanDrawing.MouseUp -= canDrawing_MouseUp_Drawing;
CanDrawing.MouseLeave -= ReferenceImage_NewSegmentDrawingMouseLeave;
Application.Current.Deactivated -= ReferenceImage_NewSegmentDrawingLostFocus;
// If the new segment has no length, delete it.
if ((_selectedLine.X1 == _selectedLine.X2) && (_selectedLine.Y1 == _selectedLine.Y2) || _selectedLine == null)
CanDrawing.Children.Remove(_selectedLine);
else
{
var point11 = new System.Drawing.Point(Convert.ToInt32(_selectedLine.X1), Convert.ToInt32(_selectedLine.Y1));
var point22 = new System.Drawing.Point(Convert.ToInt32(_selectedLine.X2), Convert.ToInt32(_selectedLine.Y2));
if (_twoLineMode)
{
if (Math.Abs(_selectedLine.X1 - _selectedLine.X2) > Math.Abs(_selectedLine.Y1 - _selectedLine.Y2))
{
_selectedLine.Stroke = Brushes.DeepPink;
if (_horizontalLines.Count > 0)
{
CanDrawing.Children.Remove(_horizontalLines[_horizontalLines.Count - 1]);
}
_horizontalLines.Add(_selectedLine);
PixelsInMillimeterTextBox.Text = GetPointsOnLine(point11, point22).Count.ToString();
}
else
{
_selectedLine.Stroke = Brushes.Green;
if (_verticalLines.Count > 0)
{
CanDrawing.Children.Remove(_verticalLines[_verticalLines.Count - 1]);
}
_verticalLines.Add(_selectedLine);
PixelsInMillimeterTextBox.Text = GetPointsOnLine(point11, point22).Count.ToString();
}
_lines.Add(_selectedLine);
}
else
{
_selectedLine.Stroke = Brushes.DeepPink;
if (_lines.Count > 0)
{
CanDrawing.Children.Remove(_lines[_lines.Count - 1]);
}
_lines.Add(_selectedLine);
PixelsInMillimeterTextBox.Text = GetPointsOnLine(point11, point22).Count.ToString();
}
}
}
#endregion Drawing
#region "Control Leave Handlers"
private void ReferenceImage_NewSegmentDrawingMouseLeave(object sender, MouseEventArgs e)
{
if (e.RightButton == MouseButtonState.Pressed)
{
canDrawing_MouseUp_Drawing(sender, e);
}
}
private void ReferenceImage_NewSegmentDrawingLostFocus(object sender, EventArgs e)
{
if (Mouse.RightButton == MouseButtonState.Pressed)
{
canDrawing_MouseUp_Drawing(sender, new MouseEventArgs(Mouse.PrimaryDevice, 0));
}
}
#endregion
private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
foreach (var line in _lines)
{
CanDrawing.Children.Remove(line);
}
_lines.Clear();
}
public static List<Point> GetPointsOnLine(System.Drawing.Point point1, System.Drawing.Point point2)
{
var points = new List<Point>();
var handle = GCHandle.Alloc(points);
try
{
LineDDA(point1.X, point1.Y, point2.X, point2.Y, GetPointsOnLineCallback, GCHandle.ToIntPtr(handle));
}
finally
{
handle.Free();
}
return points;
}
private static void GetPointsOnLineCallback(int x, int y, IntPtr lpData)
{
var handle = GCHandle.FromIntPtr(lpData);
var points = (List<Point>)handle.Target;
points.Add(new Point(x, y));
}
................................................
}
и соответствующий XAML:
<Window x:Class="DDrop.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:utility="clr-namespace:DDrop.Utility"
xmlns:cc="clr-namespace:SimpuControls;assembly=SimpuControls"
mc:Ignorable="d"
Title="DDrop" Height="629" Width="800" Icon="Resources/Icons/MainIcon.png" WindowState="Maximized">
<Grid>
<TabControl Margin="10,37,10,47">
<TabItem Header="Менеджер Серий">
<Grid>
<cc:SimpuDataGrid EnableFullTextSearch="True" Margin="10">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridTextColumn Header="Email" Binding="{Binding Email}"/>
</DataGrid.Columns>
</cc:SimpuDataGrid>
</Grid>
</TabItem>
<TabItem Header="Серия">
<TabControl Margin="10,3,10,5">
<TabItem Header="Фотографии">
<Grid Background="#FFE5E5E5" RenderTransformOrigin="0.56,0.503">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Background="Gainsboro" BorderThickness="1" Height="28" Margin="10,10,10,0" VerticalAlignment="Top">
<Grid>
<Button Grid.Row="0" Name="AddPhotoButton" HorizontalAlignment="Left" Margin="0,0,0,-2" VerticalAlignment="Top" Width="28" BorderBrush="{x:Null}" Background="{x:Null}" Height="25" Click="MenuItemChoosePhotos_OnClick">
<ContentControl Content="{StaticResource AddIcon}" Height="20"/>
</Button>
<Button Grid.Row="0" Name="DeleteInputPhotosButton" HorizontalAlignment="Left" Margin="33,0,0,-2" VerticalAlignment="Top" Width="27" Background="{x:Null}" BorderBrush="{x:Null}" Height="25" Click="DeleteAllInputPhotos_OnClick">
<ContentControl Content="{StaticResource DeleteIcon}" Height="20"/>
</Button>
</Grid>
</Border>
<DataGrid AutoGenerateColumns="False" Grid.Row="0" HorizontalAlignment="Stretch" Name="Photos" Margin="10,43,10,10" SelectionMode="Single" SelectionChanged="Photos_SelectionChanged" IsReadOnly="True" ItemsSource="{Binding DropImages}">
<DataGrid.Columns>
<DataGridTextColumn Header="Имя файла" Binding="{Binding Name}"/>
<DataGridTextColumn Header="Горизонтальный диаметр, px" Binding="{Binding XDiameterInPixels}"/>
<DataGridTextColumn Header="Вертикальный диаметр, px" Binding="{Binding YDiameterInPixels}"/>
<DataGridTextColumn Header="Горизонтальный диаметр, м" Binding="{Binding Drop.XDiameterInMeters}" />
<DataGridTextColumn Header="Вертикальный диаметр, м" Binding="{Binding Drop.YDiameterInMeters}"/>
<DataGridTextColumn Header="Радиус, м" Binding="{Binding Drop.RadiusInMeters}"/>
<DataGridTextColumn Header="Объем, кубические метры" Binding="{Binding Drop.VolumeInCubicalMeters}"/>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Name="EditInputPhotoButton" HorizontalAlignment="Left" VerticalAlignment="Top" Width="27" Background="{x:Null}" BorderBrush="{x:Null}" Height="25" Click="EditInputPhotoButton_Click">
<ContentControl Content="{StaticResource EditIcon}" Height="20"/>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Name="DeleteSingleInputPhotoButton" HorizontalAlignment="Left" VerticalAlignment="Top" Width="27" Background="{x:Null}" BorderBrush="{x:Null}" Height="25" Click="DeleteSingleInputPhotoButton_Click">
<ContentControl Content="{StaticResource DeleteIcon}" Height="20"/>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<GridSplitter HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Grid.Row="1" ResizeBehavior="PreviousAndNext"
Height="5"/>
<utility:ZoomBorder Grid.Row="2" HorizontalAlignment="Stretch" x:Name="CgsImageViewer" ClipToBounds="True" Background="Gray" Margin="10,10,13,10">
<Image x:Name="ImgCurrent" VerticalAlignment="Center" HorizontalAlignment="Center" />
</utility:ZoomBorder>
</Grid>
</TabItem>
<TabItem Header="Референс">
<Grid Background="#FFE5E5E5">
<Grid>
<Border Name="Border" BorderThickness="1" BorderBrush="#34558b" Margin="10,44,10,10">
<utility:ZoomBorder x:Name="border" ClipToBounds="True" Background="Gray">
<Canvas Name="CanDrawing"
MouseMove="canDrawing_MouseMove_NotDown"
MouseDown="canDrawing_MouseDown">
<Image VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" Stretch="Uniform" Name="ReferenceImage" Canvas.Left="0" Canvas.Top="0"/>
</Canvas>
</utility:ZoomBorder>
</Border>
</Grid>
<Button Click="ChooseReference_OnClick" Content="Выбрать референс" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="109"/>
<TextBox Name="PixelsInMillimeterTextBox" Height="20" Margin="0,10,10,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Right" Width="120"/>
<Label Content="Пикселей в миллиметре:" Margin="0,7,135,0" VerticalAlignment="Top" Height="30" Background="{x:Null}" HorizontalAlignment="Right" Width="147"/>
<Button Name="DeleteButton" HorizontalAlignment="Left" Margin="124,7,0,0" VerticalAlignment="Top" Width="27" Background="{x:Null}" BorderBrush="{x:Null}" Height="25" Click="DeleteButton_Click">
<ContentControl Content="{StaticResource DeleteIcon}" Height="20"/>
</Button>
<TextBox x:Name="IntervalBetweenPhotos" Height="20" Margin="0,10,287,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Right" Width="115"/>
<Label Content="Интервал между снимками:" Margin="0,7,407,0" VerticalAlignment="Top" Height="30" Background="{x:Null}" HorizontalAlignment="Right" Width="163"/>
</Grid>
</TabItem>
<TabItem Header="График">
</TabItem>
</TabControl>
</TabItem>
<TabItem Header="Общий график серий">
</TabItem>
<ComboBox Height="100" Width="120"/>
</TabControl>
<Menu Height="22" Margin="10,10,10,0" VerticalAlignment="Top">
<MenuItem Width="50" Height="22" Header="Меню">
<MenuItem Header="Сохранить серию">
<MenuItem.Icon>
<Rectangle Fill="#34558b" Margin="2,1,0,1" RenderTransformOrigin="0.704,0.315">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{StaticResource SaveIcon}" />
</Rectangle.OpacityMask>
</Rectangle>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Опции" Click="Options_OnClick">
<MenuItem.Icon>
<Rectangle Fill="#34558b" Margin="2,1,0,1" RenderTransformOrigin="0.704,0.315">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{StaticResource SettingsIcon}" />
</Rectangle.OpacityMask>
</Rectangle>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Выйти" Click="MenuItem_OnClick"/>
</MenuItem>
<MenuItem Click="Calculate_OnClick" Header="Рассчитать"/>
</Menu>
<Grid Margin="10,0,10,10" Background="#FFF0F0F0" Height="32" VerticalAlignment="Bottom">
<ProgressBar Height="12" Margin="0,0,10,10" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="100"/>
</Grid>
</Grid>
</Window>