蜀黍我做的工作跟IM軟件有關,UWP同時會跑在電腦和手機上。電腦和手機的使用習慣不盡一致,通常我傾向於根據窗口尺寸來進行布局的變化,但是特定的操作習慣是依賴於設備類型,而不是屏幕尺寸的,比如聊天窗口的發送消息。假設如下場景,desktop運行時要求回車鍵直接發送消息,而mobile版則要求回車鍵換行,僅能通過點擊按鈕發送消息。
第一段的鋪墊是為了今天提到的兩個主題,判斷設備類型和處理Shift+Enter的組合。
首先判斷設備類型我們使用的是Windows.System.Profile命名空間下的AnalyticsInfo類,通過AnalyticsInfo.VersionInfo.DeviceFamily這個屬性我們可以拿到當前的設備類型,小屏幕的設備類型是"Windows.Mobile",其他還是有Windows.Desktop,Windows.Xbox等。這里我們只希望單獨區分小屏幕設備,不關心其他設備類型。同時需要指出的是,隨之今后Windows設備類型的不斷擴充,該屬性可能出現的值會不斷變化,所以在使用時需要考慮到變化是否會產生bug。
public bool IsAcceptReturn { get { return AnalyticsInfo.VersionInfo.DeviceFamily == "Windows.Mobile"; } }
我們根據設備類型來定義了一個屬性IsAcceptReturn來標識是否接受回車鍵換行。
接下來進行Shift+Enter組合鍵的響應了。UWP在這一點上果然又開了歷史倒車,沒記錯的話連WinForm也無需如此麻煩,竟然要額外地儲存一個標志位來標識VirtualKey.Shift是否被按下,在此基礎之上再進一步判斷是否有Enter鍵被觸發。實際的代碼中,我使用了KeyDown事件來記錄Shift鍵的按下,同時通過KeyU事件來進行Enter鍵觸發的判斷。
private void KeyUp(KeyRoutedEventArgs e) { if (e.Key == VirtualKey.Enter) { if (_isShiftKeyPressed) { int oldIndex = Index; InputText = InputText.Replace(Environment.NewLine, "\n").Insert(Index, "\n"); Index = oldIndex + 1; } else if (IsAcceptReturn == false) { SendMessage(); } } _isShiftKeyPressed = false; } private void KeyDown(KeyRoutedEventArgs e) { if (e.Key == VirtualKey.Shift) { _isShiftKeyPressed = true; } }
在KeyUp事件中如果涉及Enter鍵的觸發,將判斷_isShiftKeyPressed字段的值,同時根據IsAcceptReturn來判斷是否不處理換行,直接發送消息。這里值得一提的是Environment.NewLine在Windows下對應的“\r\n”符號,計算字符串索引時僅作為1位處理,導致我很尷尬總是算不對Shift+Enter換行后的光標位置。無奈出下策將其替換成"\n",其中奧妙各位一試便知。程序對應的XAML如下:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <ListView Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" ItemsSource="{Binding Messages}"/> <TextBox Grid.Row="1" Grid.Column="0" Text="{Binding InputText, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectionStart="{Binding Index, Mode=TwoWay}" MaxHeight="100" AcceptsReturn="{Binding IsAcceptReturn}" TextWrapping="Wrap"> <Interactivity:Interaction.Behaviors> <Core:EventTriggerBehavior EventName="KeyUp"> <Core:InvokeCommandAction Command="{Binding KeyUpCommand,Mode=OneTime}"/> </Core:EventTriggerBehavior> <Core:EventTriggerBehavior EventName="KeyDown"> <Core:InvokeCommandAction Command="{Binding KeyDownCommand,Mode=OneTime}"/> </Core:EventTriggerBehavior> </Interactivity:Interaction.Behaviors> </TextBox> <Button Grid.Row="1" Grid.Column="1" Width="80" Command="{Binding SendMessageCommand}" Content="Send"/> </Grid>
ListView模擬聊天窗口,TextBox的Text屬性Binding到了InpuText,同時SlectionStar屬性Binding到Index,用於Shift+Enter換行時,插入\n換行符號,及確定光標位置。AcceptsReturn屬性在Mobile設備上是true,而在其他設備上就會無視回車鍵來。TextWrapping屬性也很重要,如果不設置為Wrap,即使實際的字符串是包含“\n”等換行符號,但在TextBox中也不會顯示出來。
求看到這里的各位評論一下嗨,讓俺知道還有人在看Windows UWP。
Behaviors的使用我計划后續的篇章再介紹,同時本篇的代碼使用了Mvvmlight框架,我想是時候把Mvvmlight的介紹也拾起來了!最后是完整代碼在GitHub的地址,歡迎看了批評指正哈。
https://github.com/manupstairs/UWPSamples/tree/master/UWPSamples/DeviceFamilyAndVirtualKey