トップ回答者
派生クラスのローカライズでフォントが変更されてしまう

質問
-
初めて投稿させていただきます。
「UI画面のローカライズでコントロールの位置がずれる」
という投稿と似ているのですが、未回答な状態ですので投稿させていただきます。
Visual Studio 2005 C#でプログラムを行っています。
ユーザコントロールを継承してFormコントロールを作成しているのですが、ローカライズしてビルドを行った際にフォントが勝手に変更されてしまいます。
下記のような手順でこの現象が発生しています。
何かわかる方がいらっしゃいましたらご教授お願いいたします。
【手順】
①基本クラスの作成。
ユーザコントロール
Localizable:false
Font:MS UI Gothic, 11.25pt
AutoScaleMode:True
②派生クラスにコントロールを配置。
Localizable:false
Font:MS UI Gothic, 11.25pt
AutoScaleMode:True
③Localizableをtrue、Languageを英語(米)に変更し、***.en-US.resxを作成する。
④テキストを英語化した後、ビルドするとFontがMS UI Gothic, 9ptに変更してしまう。
その後、Fontを設定しなおしてビルドすれば元に戻るのですが、編集する度にFontが9ptに変更されてしまい、困っています。
ビルド時に***.Desigener.cs内で
this.Font = null;
と指定されてしまうことが原因だと思うのですが、この現象が起こる理由、また、回避する方法がありましたらご教授お願いいたします。
回答
-
良さそうな方法がありました。
# またズレた話になっていなければ良いですが…。
上の私の投稿での1の手順で作成したコントロールを UserControl1、2の手順で作成したコントロールを UserControl2 とした場合、以下のようなプロパティの定義を UserControl1 側に行います。
方法1と方法2の2通りありますが、方法1の方は UserControl2 側でのフォントの変更までもが記録されなくなるので、方法2の方が良いと思います。
# 方法1の方は上で1度書いてますが、おそらく UserControl2 側に実装されたのではないかと考えています。
◆ 方法1
Code Snippet[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override Font Font
{
get { return base.Font; }
set { base.Font = value; }
}◆ 方法2
Code Snippetpublic override Font Font
{
get { return base.Font; }
set
{// null の代入は無視する。
if (this.Font != value && value != null)
base.Font = value;
}
}
すべての返信
-
ユーザーコントロール内にあるコントロールに対し、個別にフォントを設定すると、この問題は発生しないようです。
ただしそれでは全然解決になりませんね。どこで変になるのかを、以下のように確認してみましたところ、「B地点」でフォントが元に戻ってしまっているようでした。
# 以下、Form1 が ユーザーコントロールを貼り付けているフォーム、
# UserControl1 がユーザーコントロールの型、userControl11 がそのインスタンス変数です。Code Snippetprivate void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources =new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.userControl11 = new WindowsApplication1.UserControl1();
// ◆フォント確認◆
System.Diagnostics.Debug.WriteLine("A地点:" + this.userControl11.Font.ToString());this.SuspendLayout();
//
// userControl11
//
resources.ApplyResources(this.userControl11, "userControl11");
// ◆フォント確認◆
System.Diagnostics.Debug.WriteLine("B地点:" + this.userControl11.Font.ToString());
this.userControl11.Name = "userControl11";
・・・
}Form1 のリソースを確認してみると、たしかに「userControl11.Font」のリソースが存在しますので、単純にユーザーコントロールのフォントが反映されないという訳ではないですね…。
ということで、しかたがないので以下のようにしてみたところ、期待する結果になった感じです。
何か弊害がなければ良いですが…。Code Snippetpublic Form1()
{
InitializeComponent();// ユーザーコントロール自身のローカライズを適用しなおす
System.ComponentModel.ComponentResourceManager resources =
new System.ComponentModel.ComponentResourceManager(typeof(UserControl1));
// (UserControl1 のリソースでの "$this" は、UserControl1 自身を示す)
resources.ApplyResources(userControl11, "$this");
}ちなみに、Visual Studio 2008 でも同様でした。
単純なバグという訳ではないと思いますので、直らない可能性があるかもしれませんね。
-
ビルド時にはフォームのコンストラクタのコードは実行されませんので、配置がずれる原因は別かもしれません。
(追記:あ、InitializeComponent 内で 11pt→9pt になっているので関係あるのかもしれません。)
以前、ローカライズしていない普通のフォームで、プロジェクトを開く度にタブコントロール内のコントロールの配置がずれることを経験したことがあります。デザイナレベルの件ですが、ユーザーコントロール自身の Font プロパティをオーバーライドし、DesignerSerializationVisibilityAttribute を付加すると良さそうです。
また、フォーム側ではユーザーコントロールの Font を変更することに意味はなくなりますので、一応 BrowsableAttribute も付けてみました。こうすることで、フォーム側のリソースにはユーザーコントロールの Font 情報が記録されなくなるため、元に戻されてしまう(フォーム側での指定フォントになってしまう)ことはなくなります。
# 先ほどのコンストラクタ内のコードは不要です。
# これで配置がずれる件も回避できればいいですが。Code Snippetpublic partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override Font Font
{
get { return base.Font; }
set { base.Font = value; }
}
} -
少しわかったことを書かせてもらいます。
「UI画面のローカライズでコントロールの位置がずれる」のスレを見てみました。
まず、そこで書かれている再現方法をもう少し単純にしました。1. フォームに SplitContainer を配置する。
2. SplitContainer の BorderStyle を Fixed3D にする。
3. Panel を SplitContainer の Panel2 へ配置する。
4. 配置した Panel の Anchor を Top,Bottom,Left,Right にする。
5. フォームの Language を切り替える。手順5を繰り返すと配置した Panel のサイズは徐々に小さくなります。
手順3で配置するコントロールは Panel でなくても同じです。ポイントは上記手順の2と4だと思いますが、
nSnowBear さんの状況は、上記再現条件に当てはまりますでしょうか?~.Designer.cs の中身を見ると、BorderStyle はローカライズ対象にはなっていませんでした。
そこで試しに以下のような BorderStyle をローカライズ対象にしたコントロールを作成し、これを使って上記再現手順を行ってみましたところ、小さくなることはありませんでした。Code Snippetpublic class SplitContainerEx : SplitContainer
{
[Localizable(true)]
public new BorderStyle BorderStyle
{
get { return base.BorderStyle; }
set { base.BorderStyle = value; }
}
}ただ、この結果が何を意味するのか(直接的な原因)は、わかりませんでした。
とても惜しいところまでは来たような気がするのですが…。
なお、この件の原因は、先ほど私が書いた体験談や解像度の件とは、別なような気がしています。 -
すいません!
全然検討外れな確認をしてました。
nSnowBear さんの状況は1. [ユーザー コントロール] の作成
2. [継承されたユーザー コントロール] を、1のコントロールを継承して作成なんですね。
この場合、確かにそうなりました。
こちらでは2を行っていませんでした。
# nSnowBear さんの最初の投稿の②の手順は、コントロールを追加する手順だと思ってしまいました。# しかも、似た不都合現象を、たまたま発見してしまいましたので。
this.Font = null;
となる理由の想像ですが、上記2のコントロールとしては、Font の変更はない状態のため、デフォルトに戻っても良いという意味合いで null の代入になるのかなと思います。
これをなんとか属性の指定で制御できないかと思い、試行錯誤してみたのですが、どうにもなりませんでした。
明日、もう少しあがいてみようと思っていますが、私には期待しないでください…。 -
良さそうな方法がありました。
# またズレた話になっていなければ良いですが…。
上の私の投稿での1の手順で作成したコントロールを UserControl1、2の手順で作成したコントロールを UserControl2 とした場合、以下のようなプロパティの定義を UserControl1 側に行います。
方法1と方法2の2通りありますが、方法1の方は UserControl2 側でのフォントの変更までもが記録されなくなるので、方法2の方が良いと思います。
# 方法1の方は上で1度書いてますが、おそらく UserControl2 側に実装されたのではないかと考えています。
◆ 方法1
Code Snippet[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override Font Font
{
get { return base.Font; }
set { base.Font = value; }
}◆ 方法2
Code Snippetpublic override Font Font
{
get { return base.Font; }
set
{// null の代入は無視する。
if (this.Font != value && value != null)
base.Font = value;
}
} -
こんにちは。中川俊輔 です。
囚人さん、TH01さん、回答ありがとうございます。
nSnowBearさん、フォーラムのご利用ありがとうございます。
その後いかがでしょうか?
有用な情報と思われたため、勝手ながら囚人さん、TH01さんの回答へ回答済みチェックをつけさせていただきました。
追加の質問等ありましたら是非投稿してください!
回答済みチェックが付くことにより、有用な情報を探している方が情報を見つけやすくなります。
有用な情報と思われる回答があった場合は、なるべく回答済みボタンを押してチェックを付けてください。nSnowBearさんはチェックを解除することもできますので、ご確認ください。
それでは!