C#界面编程

2017/09/11 program 共 18818 字,约 54 分钟

入门示例

通用

  • DataContext:指定数据源类型,可以在xaml里指定,可以在cs里指定。
private void Window_Loaded(object sender, RoutedEventArgs e) {
	this.DataContext = invoiceModel;
}

Application

<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApplication1"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>

Window

<!--告诉编译器在实际运行时,忽略设计时设置的值-->
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"
<!--指定命名空间-->
xmlns:local="clr-namespace:WpfApplication1"
<!--指定数据源会绑定ActionTabViewModal,那么后面的空间数据源在绑定的时候可以直接指定该类的字段-->
<Window.DataContext>
	<local:ActionTabViewModal/>
</Window.DataContext>
<!--指定加载启动事件-->
Loaded="Window_Loaded"
// 弹出模态窗口
MyWindow dlg = new MyWindow(invoiceModel);
dlg.WindowStartupLocation = WindowStartupLocation.CenterScreen;
dlg.ShowDialog();
// 获取父窗口
MainWindow parentWindow = Application.Current.Windows.OfType<MainWindow>().FirstOrDefault();
FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}, Mode=OneTime}"

Window.CommandBindings

<Window.CommandBindings>
    <CommandBinding Command="{x:Static local:TabCommands.Close}" Executed="TabClose" />
    <CommandBinding Command="{x:Static local:TabCommands.CloseAll}" Executed="TabCloseAll" />
</Window.CommandBindings>
public partial class MainWindow : Window {
private void TabClose(object sender, ExecutedRoutedEventArgs e) {
    TabItem tab = (TabItem)e.OriginalSource;
    tabControl.Items.Remove(tab);
}
    
    public static class TabCommands {
        public static RoutedUICommand Close = new RoutedUICommand("Close", "TabClose", typeof(TabItem));
        public static RoutedUICommand CloseAll = new RoutedUICommand("Close All", "CloseAll", typeof(TabItem));
        public static RoutedUICommand Tab2 = new RoutedUICommand("Tab 2", "Tab2", typeof(TabControl));
    }
}

Window.InputBindings响应快捷键

<!--响应快捷键Ctrl + W-->
<Window.InputBindings>
	<KeyBinding Key="W" Modifiers="Control" Command="{x:Static local:TabCommands.Close}" CommandTarget="{Binding SelectedItem, ElementName=tabControl}"/>
</Window.InputBindings>

模态窗口

var win = new MyWnd();
win.ShowDialog();

非模态窗口

var win = new MyWnd();
win.Show();

Style

<!--为所有相同类型的控件设置统一的风格-->
<UserControl.Resources>
    <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
        <Setter Property="Width" Value="150" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
    </Style>
    <Style x:Key="Datepicker" TargetType="{x:Type DatePicker}" BasedOn="{StaticResource {x:Type DatePicker}}">
        <Setter Property="Width" Value="150" />
        <Setter Property="Height" Value="30" />
    </Style>
</UserControl.Resources>

预置资源

<fa:ImageAwesome Icon="Cut" Width="70" />

Binding

IsChecked="{Binding ElementName=tabControl, Path=AllowAddNew}"

克隆控件Clone

private void TabClone(TabItem original) {
    object clone;
    using (var stream = new MemoryStream()) {
        XamlWriter.Save(original, stream);
        stream.Seek(0, SeekOrigin.Begin);
        clone = XamlReader.Load(stream);
    }

    tabControl.Items.Add(clone);
    tabControl.SelectedItem = clone;
}


/// <summary>
/// Clone an element
/// </summary>
/// <param name="elementToClone"></param>
/// <returns></returns>
public static object CloneElement(object elementToClone) {
    string xaml = XamlWriter.Save(elementToClone);
    return XamlReader.Load(new XmlTextReader(new StringReader(xaml)));
}

控件

控件继承树

WPF-控件继承树

Border

边框,可以嵌套在任意控件外

Grid

<!--RowDefinition不指定时默认为1*-->
<Grid.RowDefinitions>
    <RowDefinition Height="30"/>
    <RowDefinition/>
    <RowDefinition Height="30"/>
</Grid.RowDefinitions>
<!--2列3行-->
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="30"/>
        <RowDefinition Height="30"/>
    </Grid.RowDefinitions>
</Grid>

Button

<!--透明图片按钮-->
<Button BorderThickness="0" Background="Transparent" Width="18" Height="18" Click="Close_Button_Click">
	<Image Source="close.png"/>
</Button>

?

<Style TargetType="MenuItem">
	<Setter Property="CommandTarget" Value="{Binding PlacementTarget.TemplatedParent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}" />
</Style>
<!--主菜单-->
<Menu Grid.Row="0" FontSize="15">
    <MenuItem Height="30" Header="Master">
        <MenuItem Height="30" Header="Account" Click="Account_Click"/>
        <MenuItem Height="30" Header="Account Category" Click="AccountCategory_Click"/>
    </MenuItem>
    
    <MenuItem Header="Settings">
        <MenuItem Height="30" Header="Settings 1" Click="Settings_Click"/>
        <MenuItem Height="30" Header="Settings 2" Click="Settings_Click"/>
        <MenuItem Height="30" Header="Settings 3" Click="Settings_Click"/>
    </MenuItem>

    <MenuItem Header="Help"></MenuItem>
</Menu>

ContextMenu

复用菜单项

<Window.Resources>
	<!-- 可复用的菜单项 -->
    <CompositeCollection x:Key="TabNewMenuItems" x:Shared="false">
        <MenuItem Header="Tab 1" Command="{x:Static local:TabCommands.Tab1}">
        </MenuItem>
        <MenuItem Header="Tab 2" Command="{x:Static local:TabCommands.Tab2}">
        </MenuItem>
    </CompositeCollection>
    
    <Style TargetType="MenuItem">
        <Setter Property="CommandTarget" Value="{Binding PlacementTarget.TemplatedParent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}" />
    </Style>
</Window.Resources>

后面可以在多处使用:

<Button>
    <Button.ContextMenu>
    	<ContextMenu ItemsSource="{StaticResource ResourceKey=TabNewMenuItems}">
    	</ContextMenu>
    </Button.ContextMenu>
</Button>


<ContextMenu>
    <ContextMenu.ItemsSource>
        <CompositeCollection>
            <CollectionContainer Collection="{StaticResource ResourceKey=TabNewMenuItems}" />
            <Separator />
            <MenuItem Header="Close" Command="{x:Static local:TabCommands.Close}">
            </MenuItem>
            <MenuItem Header="Close All" Command="{x:Static local:TabCommands.CloseAll}">
            </MenuItem>
            <MenuItem Header="Close All Others" Command="{x:Static local:TabCommands.CloseAllOthers}">
            </MenuItem>
        </CompositeCollection>
    </ContextMenu.ItemsSource>
</ContextMenu>

单击按钮弹出菜单

private void TabNewButton_Click(object sender, RoutedEventArgs e) {
	Button btn = (Button)sender;
	btn.ContextMenu.PlacementTarget = btn;
	btn.ContextMenu.IsOpen = true;
}

ListView

TabControl

<!--
ItemsSource:此处省略了Path=,向上找数据源,一般是DataContext,是相对于DataContext指定的类的字段。
进入到TabControl的子节点,例如TabControl.ItemTemplate,TabControl.ContentTemplate里面的Binding便是相对于每个TabControl绑定的item的字段。
在写Close_Button_Click的响应事件时,(sender as Button).DataContext就是item
-->
<TabControl Grid.Row="1" x:Name="actionTabs" ItemsSource="{Binding Tabs}" Margin="5">
    <TabControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal" Height="30" Width="170">
                <TextBlock Width="150" Text="{Binding Header}" FontSize="15" VerticalAlignment="Center"/>
                <Button Width="18" Height="18" Click="Close_Button_Click" BorderThickness="0" Background="Transparent" HorizontalAlignment="Right">
                    <Image Source="close.png"/>
                </Button>
            </StackPanel>
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.ContentTemplate>
        <DataTemplate>
            <ScrollViewer VerticalScrollBarVisibility="Auto">
                <UserControl Content="{Binding Content}" Padding="10"/>
            </ScrollViewer>
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>
namespace WpfApplication1 {
    /// view model for the TabControl To bind on
    public class ActionTabViewModal {
        // These Are the tabs that will be bound to the TabControl 
        public ObservableCollection<ActionTabItem> Tabs { get; set; }
    }
}

// This class will be the Tab int the TabControl
public class ActionTabItem {
    // This will be the text in the tab control
    public string Header { get; set; }

    // This will be the content of the tab control It is a UserControl whits you need to create manualy
    public UserControl Content { get; set; }
}
// 在写Close_Button_Click的响应事件时,(sender as Button).DataContext就是item
private void Close_Button_Click(object sender, RoutedEventArgs e) {
    ActionTabItem item = (ActionTabItem)(sender as Button).DataContext;
    // This event will be thrown when on a close image clicked
    vmd.Tabs.Remove(item);

    if (vmd.Tabs.Count() == 0) {
        actionTabs.Visibility = Visibility.Collapsed;
    }

    this.DataContext = vmd;
}

TabItem支持拖拽顺序

<!--TabItem支持拖拽顺序 复用该风格即可-->
</Window.Resources>
    <Style TargetType="TabItem">
        <Setter Property="AllowDrop" Value="True" />
        <EventSetter Event="PreviewMouseLeftButtonDown" Handler="TabItem_PreviewMouseLeftButtonDown" />
        <EventSetter Event="PreviewMouseMove" Handler="TabItem_PreviewMouseMove" />
        <EventSetter Event="Drop" Handler="TabItem_Drop" />
    </Style>
</Window.Resources>
bool _isDragging = false;
Point _dragStartingPoint;
TabItem _draggedTab;

private void TabItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
	_isDragging = false;
	_dragStartingPoint = e.GetPosition(null);
	_draggedTab = (TabItem)sender;
}

private void TabItem_PreviewMouseMove(object sender, MouseEventArgs e) {
	if (_isDragging || e.LeftButton != MouseButtonState.Pressed) return;

	Point position = e.GetPosition(null);
	if (Math.Abs(position.X - _dragStartingPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
		Math.Abs(position.Y - _dragStartingPoint.Y) > SystemParameters.MinimumVerticalDragDistance) {
		_isDragging = true;
		DragDrop.DoDragDrop(_draggedTab, _draggedTab, DragDropEffects.All);
	}
}

private void TabItem_Drop(object sender, DragEventArgs e) {
	TabItem targetTab = sender as TabItem;
	if (targetTab == null) return;
	if (!e.Data.GetDataPresent(typeof(TabItem))) return;
	TabItem sourceTab = (TabItem)e.Data.GetData(typeof(TabItem));

	if (targetTab == sourceTab) return;

	int targetIdx = tabControl.Items.IndexOf(targetTab);
	using (Dispatcher.DisableProcessing()) {
		tabControl.Items.Remove(sourceTab);
		tabControl.Items.Insert(targetIdx, sourceTab);
		tabControl.SelectedItem = sourceTab;
	}
}
<Window.Resources>
    <!-- Reset default button style. -->
    <Style TargetType="Button">
        <Setter Property="Background"
                Value="Transparent" />
        <Setter Property="Foreground"
                Value="White" />
        <Setter Property="BorderBrush"
                Value="Transparent" />
        <Setter Property="BorderThickness"
                Value="0" />
    </Style>

    <Thickness x:Key="Tab_Border_Thickness">4</Thickness>
    <Thickness x:Key="Tab_Border_Thickness_Selected">4, 4, 4, 0</Thickness>

    <!-- Menu items to create new tab -->
    <CompositeCollection x:Key="TabNewMenuItems" x:Shared="false">
        <MenuItem Header="Tab 1" Command="{x:Static local:TabCommands.Tab1}">
        </MenuItem>
        <MenuItem Header="Tab 2" Command="{x:Static local:TabCommands.Tab2}">
        </MenuItem>
    </CompositeCollection>

    <Style TargetType="MenuItem">
        <Setter Property="CommandTarget" Value="{Binding PlacementTarget.TemplatedParent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}" />
    </Style>

    <Style x:Key="TabHeaderScrollViewer"
           TargetType="ScrollViewer">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ScrollViewer">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>

                        <ScrollContentPresenter Name="PART_ScrollContentPresenter"
                                                Grid.Row="0"
                                                Grid.Column="0" />

                        <ScrollBar Name="PART_HorizontalScrollBar"
                                   Grid.Row="0"
                                   Grid.Column="1"
                                   Orientation="Horizontal"
                                   Margin="10, 0, 0, 0"
                                   Width="30"
                                   Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}">
                        </ScrollBar>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="TabControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="TabControl">
                    <DockPanel>
                        <!-- TabPanel -->
                        <ScrollViewer DockPanel.Dock="Top"
                                      VerticalScrollBarVisibility="Disabled"
                                      HorizontalScrollBarVisibility="Auto"
                                      Style="{StaticResource TabHeaderScrollViewer}">
                            <StackPanel Orientation="Horizontal"
                                        VerticalAlignment="Center">
                                <TabPanel IsItemsHost="True" />
                                <!-- New tab button -->
                                <Button VerticalAlignment="Center"
                                        Click="TabNewButton_Click">
                                    <fa:ImageAwesome Icon="Plus"
                                                     Height="7" />
                                    <Button.ContextMenu>
                                        <ContextMenu ItemsSource="{StaticResource ResourceKey=TabNewMenuItems}">
                                        </ContextMenu>
                                    </Button.ContextMenu>
                                </Button>
                            </StackPanel>
                        </ScrollViewer>

                        <!-- Content -->
                        <ContentPresenter ContentSource="SelectedContent" />
                    </DockPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="TabItem">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="TabItem">
                    <Border Name="tabItemHeaderBorder"
                            BorderThickness="{StaticResource Tab_Border_Thickness}" BorderBrush="DarkGray">
                        <StackPanel Orientation="Horizontal">
                            <TextBlock FontWeight="Bold" FontSize="15">
                                <ContentPresenter ContentSource="Header" VerticalAlignment="Center" />
                            </TextBlock>
                            <Button VerticalAlignment="Center"
                                    Command="{x:Static local:TabCommands.Close}"
                                    CommandTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}">
                                <fa:ImageAwesome Icon="Times"
                                                 Height="8"
                                                 VerticalAlignment="Center"
                                                 HorizontalAlignment="Center" />
                            </Button>
                            <StackPanel.ContextMenu>
                                <ContextMenu>
                                    <ContextMenu.ItemsSource>
                                        <CompositeCollection>
                                            <CollectionContainer Collection="{StaticResource ResourceKey=TabNewMenuItems}" />
                                            <Separator />
                                            <MenuItem Header="Close"
                                                      Command="{x:Static local:TabCommands.Close}">
                                            </MenuItem>
                                            <MenuItem Header="Close All"
                                                      Command="{x:Static local:TabCommands.CloseAll}">
                                            </MenuItem>
                                            <MenuItem Header="Close All Others"
                                                      Command="{x:Static local:TabCommands.CloseAllOthers}">
                                            </MenuItem>
                                        </CompositeCollection>
                                    </ContextMenu.ItemsSource>
                                </ContextMenu>
                            </StackPanel.ContextMenu>
                        </StackPanel>
                    </Border>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected"
                                 Value="True">
                            <Setter TargetName="tabItemHeaderBorder"
                                    Property="BorderThickness"
                                    Value="{StaticResource ResourceKey=Tab_Border_Thickness_Selected}" />
                        </Trigger>
                        <Trigger Property="IsSelected"
                                 Value="False">
                            <Setter Property="BorderBrush"
                                    Value="LightGray" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

        <Setter Property="AllowDrop"
                Value="True" />
        <EventSetter Event="PreviewMouseLeftButtonDown"
                     Handler="TabItem_PreviewMouseLeftButtonDown" />
        <EventSetter Event="PreviewMouseMove"
                     Handler="TabItem_PreviewMouseMove" />
        <EventSetter Event="Drop"
                     Handler="TabItem_Drop" />
    </Style>
</Window.Resources>

添加自定义Content

<TabControl.ContentTemplate>
	<DataTemplate>
		<ScrollViewer VerticalScrollBarVisibility="Auto">
			<UserControl Content="{Binding Content}"/>
		</ScrollViewer>
	</DataTemplate>
</TabControl.ContentTemplate>

声明一个自定义Content类:

public partial class ShortcutsListview : ContentControl {
    public ShortcutsListview() {
        InitializeComponent();
    }
}

新建一个xaml布局文件:ShortcutsListview.xaml,此处略

<ContentControl x:Class="smartrun.ShortcutsListview"
      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:smartrun"
      mc:Ignorable="d" 
      d:DesignHeight="450" d:DesignWidth="800">

    <ListView x:Name="listView" ItemsSource="{Binding}">
        
    </ListView>
</ContentControl>

声明一个TabItem模型:

// This class will be the Tab int the TabControl
public class ActionTabItem {
    // This will be the text in the tab control
    public string Header { get; set; }

    // This will be the content of the tab control It is a UserControl whits you need to create manualy
    public ContentControl Content { get; set; }
}

代码添加Tab项:

this.tabControl.Items.Add(new ActionTabItem { Header = "提醒", Content = new ShortcutsListview { DataContext = mReminders } });

ScrollViewer

<!--自动显示滚动条-->
<ScrollViewer VerticalScrollBarVisibility="Auto">
	<UserControl Content="{Binding Content}" Padding="10"/>
</ScrollViewer>

自定义滚动条样式

<!--自定义TabHeader的ScrollViewer:滚动条和TabHeader在同一行,一行两列布局,TabHeader在左边,滚动条在右侧动态显现-->
<Style x:Key="TabHeaderScrollViewer"
TargetType="ScrollViewer">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ScrollViewer">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>

                    <ScrollContentPresenter Name="PART_ScrollContentPresenter" Grid.Row="0" Grid.Column="0" />
                    <ScrollBar Name="PART_HorizontalScrollBar" Grid.Row="0" Grid.Column="1" Orientation="Horizontal" Margin="10, 0, 0, 0" Width="30" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}">
                    </ScrollBar>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style TargetType="TabControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="TabControl">
                <DockPanel>
                    <!-- TabPanel -->
                    <ScrollViewer DockPanel.Dock="Top"
                                    VerticalScrollBarVisibility="Disabled"
                                    HorizontalScrollBarVisibility="Auto"
                                    Style="{StaticResource TabHeaderScrollViewer}">
                        <StackPanel Orientation="Horizontal"
                                    VerticalAlignment="Center">
                            <TabPanel IsItemsHost="True" />
                            <!-- New tab button -->
                            <Button VerticalAlignment="Center" Click="TabNewButton_Click"/>
                        </StackPanel>
                    </ScrollViewer>

                    <!-- Content -->
                    <ContentPresenter ContentSource="SelectedContent" />
                </DockPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

UserControl

派生ContentControl,使用效果等同于ContentControl,相当于安卓里的View。

浏览器EO.WebBrowser

EO.WebBrowser,就是给.NET用的Chrome浏览器内核,可以在WinForm中嵌入Chrome浏览器,详情可以浏览官方网站。在网页上执行javascript

webView1.EvalScript("alert('hi');")

DataGrid

Expander

Separator分隔条

<!-- 竖直分隔条 -->
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" Margin="0,8" BorderBrush="LightGray" BorderThickness="1"/>

ToggleButton

  1. 定义资源并放入资源字典里面:
<Window.Resources><sys:String x:Key="myString">Hello WPF!</sys:String></Window.Resources>
  1. 引用资源,这个是一个标签扩展,其实很简单,花括号里面前面是类型名,后面是一个属性=value。
<TextBox Text="{StaticResource ResourceKey=myString}" Margin="5"/>
  1. 后台找资源的时间是用()不是[],因为这里的FindResource是窗体的方法。
string str=this.FindResource("myString") as string;

文档信息

Search

    Table of Contents