標籤:

重溫WPF知識點

(一)綁定binding,一般綁定到依賴屬性,可以雙向通知

  • 綁定到數據集合(xml文件、datatable、Collection、linq)。

public class Student
{
public int ID { get; set; }
public String Name { get; set; }
}
<GridViewColumn Header="編號" DisplayMemberBinding="{Binding ID}" Width="100"></GridViewColumn>

IList<Student> list = new ObservableCollection<Student>()
{
new Student(){ID=1,Name="狗娃"},
new Student(){ID=2,Name="狗剩"},
new Student(){ID=3,Name="鐵蛋"}
};
this.listView1.ItemsSource = list;

  • 綁定到控制項:Content="{Binding ElementName=mainWindow, Path= MyContent}"
  • 綁定到資源(動態資源可以雙向通知,靜態不可以):<TextBlock Text="{Binding Path=.,Source={StaticResource ResourceKey=myString}}"/>

(二)依賴屬性,具有屬性變化通知、限制、驗證、監聽等功能

  • DependencyProperty.Register+DependencyProperty 設置依賴屬性(還有一個附加屬性也差不多)

// 1. 使類型繼承DependencyObject類
public class Person : DependencyObject
{
// 2. 聲明一個靜態只讀的DependencyProperty 欄位
public static readonly DependencyProperty nameProperty;

static Person()
{
// 3. 註冊定義的依賴屬性
nameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Person),
new PropertyMetadata("Learning Hard",OnValueChanged));
}

// 4. 屬性包裝器,通過它來讀取和設置我們剛才註冊的依賴屬性
public string Name
{
get { return (string)GetValue(nameProperty); }
set { SetValue(nameProperty, value); }
}

private static void OnValueChanged(DependencyObject dpobj, DependencyPropertyChangedEventArgs e)
{
// 當只發生改變時回調的方法
}
}

(三)路由事件

  • 事件源發出事件,所有的控制項監聽事件。與傳統事件比較,很好的解耦了。
  • RoutedEventArgs包含了與事件有關的數據與狀態。
  • RoutedEvent標示一個事件是路由事件。

public void ButtonClicked(object sender, RoutedEventArgs e)
{
//e.OriginalSource 事件源頭
MessageBox.Show((e.OriginalSource as FrameworkElement).Name);
}

1)寫法1
<Grid x:Name="gridRoot" Background="Lime" ButtonBase.Click="ButtonClicked">
...
</Grid>
2)寫法2
this.gridRoot.AddHandler(Button.ClickEvent, new RoutedEventHandler(this.ButtonClicked));

可以自定義路由事件。自定義路由事件大體需要三個步驟:

1、聲明並註冊路由事件

2、為路由事件添加CLR事件包裝

3、創建可以激發路由事件的方法

/// <summary>
/// 自定義個一個時間控制項
/// </summary>
public class TimeButton : Button
{
//聲明並註冊路由事件
/*
* 1、第一個參數ReportTime 為路由事件的名稱
* 2、第二個參數是路由事件的策略,包括Bubble冒泡式,Tunnel隧道式,Direct直達式(和直接事件類似)
* 3、第三個參數用於指定事件處理器的類型
* 4、第四個參數用於指定事件的宿主是哪一種類型
*/
public static readonly RoutedEvent ReportTimeEvent = EventManager.RegisterRoutedEvent
("ReportTime", RoutingStrategy.Bubble, typeof(EventHandler<ReportTimeEventArgs>), typeof(TimeButton));

//CLR事件包裝器
public event RoutedEventHandler ReportTime
{
add { this.AddHandler(ReportTimeEvent, value); }
remove { this.RemoveHandler(ReportTimeEvent, value); }
}

//激發路由事件,借用Click事件的激發方法
protected override void OnClick()
{
base.OnClick();

ReportTimeEventArgs args = new ReportTimeEventArgs(ReportTimeEvent,this);
args.ClickTime = DateTime.Now;
this.RaiseEvent(args);
}

(四)命令

  • 命令:寫一個類,實現ICommand介面。這個類就是一個命令類。或者使用已存在的命令類:RoutedCommand或者RoutedUICommand等。

public class CommandBase<T> : ICommand
{
#region Private Fields
private readonly Action<object> _command;
private readonly Func<object, bool> _canExecute;
#endregion
#region Constructor
/// <summary>
/// 實例化一個CommandBase對象
/// </summary>
/// <param name="command">委託一個有object類型參數的命令執行函數</param>
/// <param name="canExecute">委託一個有object類型參數的命令是否能被執行的函數(可選)</param>
/// <exception cref="ArgumentNullException">參數command不可以為null引用</exception>
public CommandBase(Action<object> command, Func<object, bool> canExecute = null)
{
if (command == null)
throw new ArgumentNullException("command");
_canExecute = canExecute;
_command = command;
}
#endregion
#region ICommand Members
public void Execute(object parameter)
{
_command(parameter);
}
public bool CanExecute(object parameter)
{
if (_canExecute == null)
return true;
return _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
#endregion
}

  • 命令源:實現了ICommandSource介面的類,Button等控制項都實現了這個介面

ICommand Command { get; }
object CommandParameter { get; }
IInputElement CommandTarget { get; }

  • 命令目標:命令的接受者。指的是實現了IInputElement介面的類。系統自帶的命令一般與命令目標有關係。鬼知道在RoutedCommand中命令目標使用了什麼邏輯。

// 摘要:
// 確定此 System.Windows.Input.RoutedCommand 在其當前狀態是否可以執行。
//
// 參數:
// parameter:
// 用戶定義的數據類型。
//
// target:
// 命令目標。
//
// 返回結果:
// 如果可以對當前命令目標執行此命令,則為 true;否則為 false。
//
// 異常:
// System.InvalidOperationException:
// target 不是 System.Windows.UIElement 或 System.Windows.ContentElement。
[SecurityCritical]
public bool CanExecute(object parameter, IInputElement target);
//
// 摘要:
// 對當前命令目標執行 System.Windows.Input.RoutedCommand。
//
// 參數:
// parameter:
// 要傳遞到處理程序的用戶定義的參數。
//
// target:
// 要在其中查找命令處理程序的元素。
//
// 異常:
// System.InvalidOperationException:
// target 不是 System.Windows.UIElement 或 System.Windows.ContentElement。
[SecurityCritical]
public void Execute(object parameter, IInputElement target);
private RoutedCommand rouutedCommand = new RoutedCommand("Clear", typeof(MainWindow));
public MainWindow()
{
InitializeComponent();
//把命令賦值給命令源,並定義快捷鍵
this.btn1.Command = rouutedCommand;
this.rouutedCommand.InputGestures.Add(new KeyGesture(Key.C, ModifierKeys.Alt));
//指定命令目標
this.btn1.CommandTarget = txt1;

//創建命令關聯
CommandBinding commandBinding = new CommandBinding();
commandBinding.Command = rouutedCommand;//只關注與rouutedCommand相關的命令
commandBinding.CanExecute += new CanExecuteRoutedEventHandler(cb_CanExecute);
commandBinding.Executed += new ExecutedRoutedEventHandler(cb_Execute);
//把命令關聯安置在外圍控制項上
this.CommandBindings.Add(commandBinding);
}

private void cb_Execute(object sender, ExecutedRoutedEventArgs e)
{
txt1.Clear();
//避免事件繼續向上傳遞而降低程序性能
e.Handled = true;
}
//當探測命令是否可執行的時候該方法會被調用
private void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
if (string.IsNullOrEmpty(txt1.Text))
{
e.CanExecute = false;
}
else
{
e.CanExecute = true;
}
//避免事件繼續向上傳遞而降低程序性能
e.Handled = true;
}

  • 命令關聯:CommandBinding類定義如下:

public ICommand Command { get; set; }

public event CanExecuteRoutedEventHandler CanExecute;
public event ExecutedRoutedEventHandler Executed;
public event CanExecuteRoutedEventHandler PreviewCanExecute;
public event ExecutedRoutedEventHandler PreviewExecuted;

  • 過程解析:當命令源確定了命令目標後(人為指定或焦點判斷),就會不停地向命令目標詢問,命令目標就會不停地發送PreviewCanExecute和CanExecute事件,這兩個附加事件就會沿著元素樹向上傳遞,然後被命令關聯捕獲,命令關聯將命令能不能發送報告給命令。若可以發送命令,則命令源將發送命令給命令目標,命令目標會發送PreviewExecuted和Executed事件,這兩個附加也會沿著元素樹向上傳遞,然後被命令關聯捕獲,完成一些後續工作。

(五)模板

  • 控制項模板ControlTemplate:綁定到控制項的Template屬性或者Style的Template屬性,包括外觀和觸發器兩個重要屬性。
  • Style:可以使用Style設置控制項的某些屬性,包括Template模板等。
  • 數據模板DataTemplate:綁定到控制項的CellTemplate或ContentTemplate或ItemTemplate屬性。決定數據顯示的樣式。
  • 面板模板ItemPanelTemplate:綁定到控制項的ItemPanel屬性。
  • 三者關係:

  • 使用方式:先定義一個模板,然後在把對應的key應用到控制項對應的屬性中,對於控制項模板,應用的是控制項的Template,對於數據模板,應用的是控制項的ItemTemplate屬性,對於面板模板,應用的是控制項的ItemsPanel屬性

(六)資源

  • 二進位資源:右擊項目屬性》資源》添加字元串、圖片、音頻、圖像等。
  • 邏輯資源:在XAML中定義的<window.Resources></window.Resources>或者在ResourceDirectory字典中定義的資源,然後再XAML引用。
  • 資源的使用方式:後台引用、前台用擴展標記引用都可以。

(七)擴展

  • x:static標記:指向的對象通常是後台代碼里的某個靜態類,可以指向Properties.Resources.字元串資源(二進位資源)。
  • StaticResource標記:指向XAML中的邏輯資源
  • DynamicResource標記:指向XAML中的動態資源,資源變化,屬性隨著變化。
  • RelativeSource標記:指向對象不知道,綁定到自身或者父對象等。
  • TemplateBinding標記:綁定到模板的一個屬性。這個模板又屬於某個控制項。
  • x:Key標記:唯一標示
  • X:Name標記:唯一標示
  • X:Type標記:類型
  • X:Null標記:設置為Null

推薦閱讀:

F#.NET周報 2018第34周Ionide下載量100萬
.NET和F#周報2018第39-40周.NET Core 3.0 Infer.NET Blazor
【ASP.Net Core學習筆記】(一)與資料庫工作

TAG:.NET |