smallgeek

Swing god gun, I need it low demon

バインディングしたプロパティの値をリソースのキーにする

使い方

<TextBlock Text="{sample:ResourceBinding Path=ResourceName}" />

実装

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;

namespace Sample
{
    /// <summary>
    /// リソースキーにバインディングするためのマークアップ。
    /// </summary>
    public class ResourceBinding : MarkupExtension
    {
        /// <summary>
        /// リソースへの参照情報を取得する。
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static object GetResourceReference(DependencyObject obj)
        {
            return obj.GetValue(ResourceReferenceProperty);
        }

        /// <summary>
        /// リソースへの参照情報を設定する。
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="value"></param>
        public static void SetResourceReference(DependencyObject obj, object value)
        {
            obj.SetValue(ResourceReferenceProperty, value);
        }

        /// <summary>
        /// ResourceReference 依存関係プロパティ。
        /// </summary>
        public static readonly DependencyProperty ResourceReferenceProperty =
            DependencyProperty.RegisterAttached(
                "ResourceReference",
                typeof(object),
                typeof(ResourceBinding),
                new PropertyMetadata(null));

        /// <summary>
        /// バインディング ソース オブジェクトとして使用するオブジェクトを取得または設定。
        /// </summary>
        public object Source { get; set; }

        /// <summary>
        /// バインディング ソース プロパティへのパスを取得または設定。
        /// </summary>
        public PropertyPath Path { get; set; }

        /// <summary>
        /// 使用する XML バインディング ソースの値を返す XPath クエリを取得または設定。
        /// </summary>
        [DefaultValue(null)]
        public string XPath { get; set; }

        /// <summary>
        /// バインディングのデータ フローの方向を示す値を取得または設定。
        /// </summary>
        [DefaultValue(BindingMode.Default)]
        public BindingMode Mode { get; set; }

        /// <summary>
        /// バインディング ソースを更新するタイミングを決定する値を取得または設定。
        /// </summary>
        [DefaultValue(UpdateSourceTrigger.Default)]
        public UpdateSourceTrigger UpdateSourceTrigger { get; set; }

        /// <summary>
        /// バインディング ターゲットの位置に対して相対的な位置を指定することにより、バインディング ソースを取得または設定。
        /// </summary>
        [DefaultValue(null)]
        public RelativeSource RelativeSource { get; set; }

        /// <summary>
        /// バインディング ソース オブジェクトとして使用する要素の名前を取得または設定。
        /// </summary>
        [DefaultValue(null)]
        public string ElementName { get; set; }

        /// <summary>
        /// <see cref="ResourceBinding"/> クラスの新しいインスタンスを生成。
        /// </summary>
        public ResourceBinding()
        {

        }

        /// <summary>
        /// バインディングするプロパティへのパスを指定して <see cref="ResourceBinding"/> クラスの新しいインスタンスを生成。
        /// </summary>
        /// <param name="path">バインディングするプロパティへのパス。</param>
        public ResourceBinding(string path)
        {
            Path = new PropertyPath(path);
        }


        /// <summary>
        /// マークアップの使用元に値を提供する。
        /// </summary>
        /// <param name="serviceProvider">カスタムサポート用オブジェクト。</param>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var provideValueTarget = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
            if (provideValueTarget == null)
            {
                return null;
            }

            // テンプレートがパースされるときは System.Windows.SharedDp が格納されている
            // this を返しておくと再評価時にリソースが反映される
            if (provideValueTarget.TargetObject.GetType().FullName == "System.Windows.SharedDp")
            {
                return this;
            }

            var targetObject = provideValueTarget.TargetObject as FrameworkElement;
            var targetProperty = provideValueTarget.TargetProperty as DependencyProperty;

            if (targetObject == null || targetProperty == null)
            {
                return null;
            }


            // 中継用プロパティにバインディング
            var binding = new Binding
            {
                Path = Path,
                XPath = XPath,
                Mode = Mode,
                UpdateSourceTrigger = UpdateSourceTrigger
            };

            if (RelativeSource != null)
            {
                binding.RelativeSource = RelativeSource;
            }

            if (ElementName != null)
            {
                binding.ElementName = ElementName;
            }

            if (Source != null)
            {
                binding.Source = Source;
            }
            var expr = BindingOperations.SetBinding(targetObject, ResourceReferenceProperty, binding);

            var descriptor = DependencyPropertyDescriptor.FromProperty(ResourceReferenceProperty, targetObject.GetType());
            descriptor.AddValueChanged(targetObject, (s, e) =>
            {
                // 中継した値を取得してリソースへの参照を作成
                var changeKey = targetObject.GetValue(ResourceReferenceProperty);
                var newDre = new DynamicResourceExtension(changeKey);
                targetObject.SetValue(targetProperty, newDre.ProvideValue(new ServiceValueProvider()));
            });

            // 初期値を作るための更新
            //   Prism の ViewModelLocator のような InitializeComponent 内で ViewModel を生成し DataContext に設定している場合は以下の処理が必要となる
            //   そうでない場合は return null で問題なく動く
            expr.UpdateSource();

            // 初期表示にはこの参照が使用される
            var key = targetObject.GetValue(ResourceReferenceProperty);

            if (key != null)
            {
                var dre = new DynamicResourceExtension(key);
                return dre.ProvideValue(new ServiceValueProvider());
            }

            return null;
        }

        /// <summary>
        /// バインディング情報を生成する。
        /// </summary>
        /// <returns></returns>
        private Binding CreateBinding()
        {
            var baseBinding = new Binding
            {
                Path = Path,
                XPath = XPath,
                Mode = Mode,
                UpdateSourceTrigger = UpdateSourceTrigger
            };

            if (RelativeSource != null)
            {
                baseBinding.RelativeSource = RelativeSource;
            }

            if (ElementName != null)
            {
                baseBinding.ElementName = ElementName;
            }

            if (Source != null)
            {
                baseBinding.Source = Source;
            }

            return baseBinding;
        }
    }

    /// <summary>
    /// DynamicResource を C# コードで指定するために使用するクラス。
    /// </summary>
    public class ServiceValueProvider : IServiceProvider, IProvideValueTarget
    {
        public object TargetObject { get; private set; }

        public object TargetProperty { get; private set; }

        public object GetService(Type serviceType)
        {
            if (serviceType == typeof(IProvideValueTarget))
            {
                return this;
            }
            return null;
        }

        internal void SetData(object targetObject, object targetProperty)
        {
            TargetObject = targetObject;
            TargetProperty = targetProperty;
        }
    }
}

C# で USB メモリの情報を取得する

ManagementObjectSearcher を使用する。(System.Management.dll の参照が必要)

var mos = new ManagementObjectSearcher("Select * from Win32_DiskDrive where InterfaceType='USB'");
// SELECT * FROM Win32_PnPEntity where DeviceID Like 'USB%' 

foreach (var mo in mos.Get())
{
    Console.WriteLine(mo);

    foreach (var prop in mo.Properties)
    {
        Console.WriteLine($"  {prop.Name} : {prop.Value}");
    }
    //インデクサで個別取得できる
    //var pnp = mo["PNPDeviceID"].ToString();
    //Console.WriteLine(pnp);
}

Docker for Windows を使用して調べたことの簡易な備忘録

※ Docker 17.12.0-ce-win47 を使用

外部からコンテナに接続する

ポートフォワーディングを使用する。起動時に -p オプションを使用してホストとコンテナのポートを対応付ける。 docker run -d --name コンテナ名 -p ホスト側のポート:コンテナ側のポート image

コンテナからホストに接続する

eth0 のゲートウェイがコンテナからホストにアクセスするためのアドレスになる。

コンテナにログインしてコマンドを実行する

docker exec -it コンテナ名 コマンド

Docker network

docker network ls で確認できるネットワークには bridge host none があり、デフォルトは bridgebridge では Docker Engine 上のネットワークにコンテナが配置される。Docker ホストが属するネットワークとは異なる。

VPN

Docker 起動中に VPN 接続すると docker プロセスに接続できなくなる。起動してから VPN に接続する。