◇Pile Up◇ --Keenag Blog--

プログラミング備忘録ブログです。C#、WPFの記事が中心となります。

UPDATEで採番し直したい

数値がばらばらになっているカラムを1から採番し直したいときに使用できるクエリの紹介です。
以下のようなテーブルがあります。
今回は、HogeNoとSortNoの昇順で行番号を取得し、その行番号を使用してRecordIDを採番しなおします。

HogeNo SortNo RecordID
1000 1 32
1000 2 23
2000 1 12
2000 2 55
2000 3 99
UPDATE TEST
SET RecordID = NewRecordID
FROM TEST T
INNER JOIN 
    ( SELECT
         HogeNo
        ,SortNo
        , ROW_NUMBER() OVER(ORDER BY HogeNo ASC,SortNo ASC) AS NewRecordID
      FROM
        TEST
    ) TEMP
ON T.HogeNo = TEMP.HogeNo
AND T.SortNo = TEMP.SortNo




結果はこのようになります。

HogeNo SortNo RecordID
1000 1 1
1000 2 2
2000 1 3
2000 2 4
2000 3 5




以下の1文を変更することで、好きな順序で採番が可能です。

ROW_NUMBER() OVER(ORDER BY HogeNo DESC,SortNo DESC)
HogeNo SortNo RecordID
2000 3 1
2000 2 2
2000 1 3
1000 2 4
1000 1 5

Git上で消したはずのremoteブランチが残っている

Git上で削除したはずのremoteブランチは、VisualStudio上でFetchしても残念ながら VisualStudio上では表示されたままになってしまいます。
これは、ローカルに複製された設定が残っているためです。
コマンドプロンプトを開き、

git fetch -p 

を実行すると、remoteブランチの状態とVisualStudio上のチームエクスプローラーの remoteブランチの状態が統一されます。

【WPF】選択・コピー不可で見た目も変わらないコントロールを作りたい

WPFでコントロールを読み取り専用にしたいとき、コントロールのIsReadOnlyを"True"にし、実現するときが多いかと思います。
今回は、

  • 読み取り専用にしたいけど、選択・コピーはされたくない。
  • IsEnabledプロパティをFalseにして、グレーアウトはさせたくない。(見た目は変えたくない)

というときに使用できる便利なプロパティ、IsHitTestVisibleの説明となります。
上記を満たしたいとき、以下の1行をコントロールに追加するだけで、見た目は変わらず、選択もコピーもできないコントロールを作成することができます。

 <TextBox  IsHitTestVisible="False"  …

見た目のイメージはこのようになります。 f:id:Keenag:20171221150257p:plain 今回はTextBoxでサンプルを作りましたが、ボタン、プルダウン、チェックボックス等にも、もちろん使用可能です。 今回はこれで終わりです。それではまた。

【XAML】RadioButtonは選択されているボタンだけタブ遷移したい

今回は、XAMLのRadioButtonのタブ遷移の話です。
デフォルトの設定では、グルーピングされているRadioButtonは、選択されている、されていないに関わらず、すべてのRadioButtonにタブフォーカスが当たる仕様となっています。
「選択されているラジオボタンだけタブ遷移させたい」
そんなときありますよね?あります。

そんなときは、RadioButtonの親要素のStackPanelコントロールに以下のプロパティを追加してやればいいんです。

KeyboardNavigation.TabNavigation="Once" 

実際のコードでは次のように使います。

 <Grid>
        <Grid Height="60" VerticalAlignment="Top">
            <StackPanel  Orientation="Horizontal"
                         HorizontalAlignment="Center"
                         KeyboardNavigation.TabNavigation="Once"
                         KeyboardNavigation.TabIndex="0" >
                <RadioButton Content="Button1"
                                 VerticalContentAlignment="Center"
                                 GroupName="RadioGroup"
                                 />
                <RadioButton Content="Button2"
                                 VerticalContentAlignment="Center"
                                 Margin="30,0,0,0"
                                 GroupName="RadioGroup"
                                 />
            </StackPanel >
        </Grid>
        <Button Content="Button" Height="30" Width="75"  TabIndex="1" />
    </Grid>

こうすることで、StackPanelの中の要素には、1度しかタブフォーカスが当たらないように設定できます。 今回はRadioButtonの例で紹介しましたが、ほかのコントロールでも同様に制御が可能です。 以下、MSの公式サイトの情報です。
KeyboardNavigationMode 列挙型
今回はこれで終わりです。それではまた。

【WPF】ポップアップで入力された値を親画面で受け取る方法

今回は、WPFで親画面でポップアップを出した際に、入力された値を親画面で受け取る方法に ついてサンプルアプリケーションをつくったので、説明してきたいと思います。

各クラスの役割

各クラスの役割はこんな感じです。 なお、いくつかのクラスは省略しています。詳細はサンプルコードを参考にしてください。

クラス名 役割
MainWindow.xaml ポップアップ表示元の親画面のXAML
ChildDialog.xaml 親画面から表示されるポップアップのXAML
InputValueNotification.cs 子から親へ値の橋渡しをするNotificationクラス
MainWindowViewModel.cs ポップアップ表示元の親画面のViewModelクラス
ChildDialogViewModel.cs 親画面から表示されるポップアップのViewModelクラス

MainWindow.xaml

親画面では、ポップアップで入力された文字を表示するTextBoxが用意されています。
また、ポップアップを表示するための「ポップアップ表示」ボタンを配置されています。このボタンを押下することで、prismを使用し、PopupWindowActionでポップアップが表示されます。

<Window x:Class="NotificationSample.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="http://prismlibrary.com/"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:views="clr-namespace:NotificationSample.Views"
        prism:ViewModelLocator.AutoWireViewModel="True"
        Title="NotificationSample" Height="350" Width="525"
        Background="LightSlateGray">
    <i:Interaction.Triggers>
        <prism:InteractionRequestTrigger SourceObject="{Binding OpenChildDialogRequest}">
            <prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True" >
                <prism:PopupWindowAction.WindowContent>
                    <views:ChildDialog />
                </prism:PopupWindowAction.WindowContent>
            </prism:PopupWindowAction>
        </prism:InteractionRequestTrigger>
    </i:Interaction.Triggers>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="100"/>
            <RowDefinition Height="100"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="180"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Label Grid.Row="0"
               Grid.Column="0"
               Content="ポップアップで入力された文字:"
               FontSize="12"
               HorizontalAlignment="Right"
               VerticalAlignment="Bottom"/>
        <TextBox Grid.Row="0"
                 Grid.Column="1"
                 Height="30"
                 HorizontalAlignment="Left"
                 VerticalAlignment="Bottom"
                 Width="200"
                 Text="{Binding OwnerInputValue.Value}"/>
        <Button Grid.Row="1"
                Grid.Column="1"
                Content="ポップアップ表示"
                Width="150"
                Height="50"
                HorizontalAlignment="Left"
                VerticalAlignment="Center"
                Command="{Binding OpenChildDialogCommand}"/>
    </Grid>
</Window>

ChildDialog.xaml

ポップアップ画面では、親画面に引き継ぎたい文字を入力するTextBoxと、ポップアップを閉じ、親画面へ戻る「親画面へ」ボタンが配置されています。

<UserControl x:Class="NotificationSample.Views.ChildDialog"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/"             
             prism:ViewModelLocator.AutoWireViewModel="True"
             Width="525"
             Height="350"
             Background="LightSlateGray">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="100"/>
            <RowDefinition Height="100"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="180"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Label Grid.Row="0"
               Grid.Column="0"
               Content="親画面に引き継ぐ文字:"
               FontSize="12"
               HorizontalAlignment="Right"
               VerticalAlignment="Bottom"/>
        <TextBox Grid.Row="0"
                 Grid.Column="1"
                 Height="30"
                 HorizontalAlignment="Left"
                 VerticalAlignment="Bottom"
                 Width="200"
                 Text="{Binding ChildInputValue.Value}"/>
        <Button Grid.Row="1"
                Grid.Column="1"
                Content="親画面へ"
                Width="150"
                Height="50"
                HorizontalAlignment="Left"
                VerticalAlignment="Center"
                Command="{Binding NavigateOwnerCommand}"/>
    </Grid>
</UserControl>

InputValueNotification.cs

prismのNotificationクラスを継承したInputValueNotificationクラスには、プロパティにInputValueを定義します。このプロパティにポップアップ内のTextBoxで入力された値を詰め、親画面のViewModelで値を受け取ります。

using Prism.Interactivity.InteractionRequest;

namespace NotificationSample.ViewModels
{
    public class InputValueNotification : Notification
    {
        public string InputValue { get; set; }
    }
}

MainWindowViewModel.cs

OwnerInputValueは、ポップアップで入力された値を表示するために使用するプロパティです。
OpenChildDialogCommandは、親画面で「ポップアップ表示」ボタンを押下した際に呼ばれるCommandです。
OpenChildDialogRequestは、ポップアップの表示をViewに通知するときに使用されます。
OpenChildDialogCommandが実行されると、inputValueNotificationを引数にOpenChildDialogRequestが呼ばれ、 ポップアップが表示されます。
引数で渡したinputValueNotificationが保持するInputValueプロパティがポップアップ側で変更されていたら、OwnerInputValueに、InputValueプロパティの値をセットします。

using Prism.Commands;
using Prism.Interactivity.InteractionRequest;
using Prism.Mvvm;
using Reactive.Bindings;

namespace NotificationSample.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {   
        public ReactiveProperty<string> OwnerInputValue { get; } = new ReactiveProperty<string>();

        public DelegateCommand OpenChildDialogCommand { get; }

        public InteractionRequest<InputValueNotification> OpenChildDialogRequest { get; } = new InteractionRequest<InputValueNotification>();
        
        public MainWindowViewModel()
        {
            OpenChildDialogCommand = new DelegateCommand(() =>
            {
                var inputValueNotification = new InputValueNotification() { Title = "NotificationSample" };
                OpenChildDialogRequest.Raise(inputValueNotification);
                if (inputValueNotification.InputValue != null)
                {
                    OwnerInputValue.Value = inputValueNotification.InputValue;
                }
            });

        }
    }
}

ChildDialogViewModel.cs

ChildInputValueはポップアップのTextBoxのTextにBindingされているプロパティです。 ポップアップで「親画面へ」ボタンが押下された際はNavigateOwnerCommandが実行されます。
NavigateOwnerCommandが実行された際は、ChildInputValueの値をInputValueNotificationのInputValueプロパティに詰め、FinishInteractionでポップアップを閉じます。

using Prism.Commands;
using Prism.Interactivity.InteractionRequest;
using Prism.Mvvm;
using Reactive.Bindings;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NotificationSample.ViewModels
{
    public class ChildDialogViewModel : BindableBase, IInteractionRequestAware
    {
        public INotification Notification { get; set; }
        public Action FinishInteraction { get; set; }
        public ReactiveProperty<string> ChildInputValue { get; } = new ReactiveProperty<string>();


        public DelegateCommand NavigateOwnerCommand => new DelegateCommand(() =>
        {
            ((InputValueNotification)Notification).InputValue = ChildInputValue.Value;
            FinishInteraction();
        });
    }
}

実行結果

実行結果は次のようになります。
ポップアップのTextBoxで入力された値を親画面で受け取れていることが確認できます。

サンプルコード

以下に公開しています。
https://github.com/Keenag/SampleCode/tree/master/NotificationSample

【WPF】タブ順指定ではまりかけた話

XAMLではTabIndexを指定することで、ユーザのタブ操作によるフォーカスの順番を設定することができますが、 Windowの中にUserControlを表示するような画面の場合、少しはまりかけたので、備忘録として残します。 以下サンプルコードで説明していきます。
なお、今回も一部のソースコードの説明は割愛しています。詳細はサンプルコードを参考にしてください。

MainWindow.xaml

MainWindow.xamlクラスは、WindowのLoadedイベントで、MainwindowViewModel.csのNavigateCommandが呼ばれ、ContentControl部分にMainWindowViewModel.csで指定したUserControlが組み込まれるという作りになっています。

<Window x:Class="TabIndexSample.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:prism="http://prismlibrary.com/"
        prism:ViewModelLocator.AutoWireViewModel="True"
        Title="TabIndexSample" Height="350" Width="525">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandAction Command="{Binding NavigateCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <Grid>
        <ContentControl prism:RegionManager.RegionName="ContentRegion"
                        FocusVisualStyle="{StaticResource FocusVisualStyleKey}"/>
    </Grid>
</Window>

HogeUserControl.xaml

HogeUserControl.xamlは、MainWindow.xamlのContentControlに表示されるUserControlで、 TabIndexでユーザのタブ操作を制御しています。

<UserControl x:Class="TabIndexSample.Views.HogeUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/"             
             prism:ViewModelLocator.AutoWireViewModel="True"
             Height="350"
             Width="525"
             Background="LightSlateGray">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="100"/>
            <RowDefinition Height="100"/>
            <RowDefinition Height="100"/>
        </Grid.RowDefinitions>
        <Label Grid.Row="0"
               Content="TabIndex1"
               HorizontalAlignment="Left"
               VerticalAlignment="Center"
               Margin="90,0,0,0"/>
        <TextBox Grid.Row="0"
                 Width="200"
                 Height="30"
                 TabIndex="1"
                 FocusVisualStyle="{StaticResource FocusVisualStyleKey}"/>
        <Label Grid.Row="1"
               Content="TabIndex2"
               HorizontalAlignment="Left"
               VerticalAlignment="Center"
               Margin="90,0,0,0"/>
        <TextBox Grid.Row="1"
                 Width="200"
                 Height="30"
                 TabIndex="2"
                 FocusVisualStyle="{StaticResource FocusVisualStyleKey}"/>
        <Label Grid.Row="2"
               Content="TabIndex0"
               HorizontalAlignment="Left"
               VerticalAlignment="Center"
               Margin="90,0,0,0"/>
        <TextBox Grid.Row="2"
                 Width="200"
                 Height="30"
                 TabIndex="0"
                 FocusVisualStyle="{StaticResource FocusVisualStyleKey}"/>
    </Grid>
</UserControl>

実行結果(修正前)

このソースコードで実行すると、実行結果はこのようになります。

HogeUserControl.xaml内のTab操作を終えると、タブのフォーカスが画面全体にあたってしまいます。
これでは、意図していたタブ操作ではありません。 そこで、HogeUserControlのUserControlタグに

IsTabStop="False"

を追加してみたのですが、結果は変わりません。
UserContorolの表示元であるMainWindow.xamlのContentControlにIsTabStop="False"を追加することで解決することができました。

        <ContentControl prism:RegionManager.RegionName="ContentRegion"
                        FocusVisualStyle="{StaticResource FocusVisualStyleKey}"
                        IsTabStop="False"/>

実行結果(修正後)

修正後の実行結果はこのようになります。
無事、画面全体へのフォーカスが外れました。

サンプルコード

以下に公開しています。
https://github.com/Keenag/SampleCode/tree/master/TabIndexSample

【WPF】ReactivePropertyを使用してボタンの活性非活性を制御する方法

ReactivePropertyはMVVM+リアクティブプログラミングを快適にサポートしてくれるライブラリです。
今回は、ReactivePropertyを使用して、ボタンの制御サンプルを作ってみたので、備忘録として残したいと思います。

なお、ReactivePropertyについてもっと知りたい方は、MVVMをリアクティブプログラミングで快適にReactivePropertyオーバービューをご覧になってみてください。

では、サンプルプログラムを見ていきましょう。

MainWindow.xaml

MainWindow.xamlクラスには、ボタンの活性、非活性を制御するグルーピングされた「活性」ラジオボタン、「非活性」ラジオボタンを配置します。 「活性」ラジオボタンのIsCheckedプロパティには、IsActiveをバインディングしています。 ボタンには、CommandプロパティにHogeCommandをバインディングしています。

<Window x:Class="ReactiveCommandSample.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="http://prismlibrary.com/"
        prism:ViewModelLocator.AutoWireViewModel="True"
        Title="ReactiveCommandSample"
        Height="350"
        Width="525"
        Background="LightSlateGray">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="80"/>
            <RowDefinition Height="40"/>
            <RowDefinition Height="50"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <RadioButton Grid.Row="0"
                     Grid.Column="1"
                     Content="活性"
                     VerticalAlignment="Bottom"
                     HorizontalAlignment="Left"
                     TabIndex="0"
                     HorizontalContentAlignment="Left"
                     VerticalContentAlignment="Center"
                     Padding="1"
                     GroupName="HogeRadio"
                     IsChecked="{Binding IsActive.Value}"
                     Height="27"
                     Width="126"
                     FocusVisualStyle="{x:Null}"
                     />
        <RadioButton Grid.Row="1"
                     Grid.Column="1"
                     Content="非活性"
                     VerticalAlignment="Bottom"
                     HorizontalAlignment="Left"
                     TabIndex="1"
                     VerticalContentAlignment="Center"
                     GroupName="HogeRadio"
                     Height="27"
                     Width="139"
                     FocusVisualStyle="{x:Null}"
                     />
        <Button Grid.Row="2"
                Grid.Column="1"
                Content="Button"
                HorizontalAlignment="Left"
                VerticalAlignment="Bottom"
                Width="99"
                Height="34"
                Command="{Binding HogeCommand}"/>
    </Grid>
</Window>

MainWindowViewModel.cs

MainWindowViewModelクラスでは、「活性」ボタンの変更通知を受け取るReactiveProperttyのIsActiveを定義します。また、ReactiveCommandのHogeCommandを定義します。
HogeCommandは、IsActiveがTrueの時のみ(「活性」ボタンが選択されている時のみ)活性化し、押下された際はOnClickメソッドが呼ばれます。

using Prism.Mvvm;
using Reactive.Bindings;
using System.Reactive.Linq;

namespace ReactiveCommandSample.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        public ReactiveProperty<bool> IsActive { get; } = new ReactiveProperty<bool>(true);
        public ReactiveCommand HogeCommand { get; }

        public MainWindowViewModel()
        {
            HogeCommand = IsActive.Select(x => x == true).ToReactiveCommand();
            HogeCommand.Subscribe(OnClick);
        }

        public void OnClick()
        {
            //ボタンが押下された際の処理
        }
    }
}

実行結果

実行結果はこのようになります。
「活性」ラジオボタンが押下されているときは、ボタンが活性化しています。 f:id:Keenag:20171008225521p:plain

「非活性」ラジオボタンが押下されているときは、ボタンが非活性化しています。 f:id:Keenag:20171008225611p:plain

サンプルコード

以下に公開しています。
https://github.com/Keenag/SampleCode/tree/master/ReactiveCommandSample