有没有关于在 WPF 中进行 AppBar 停靠(例如锁定到屏幕边缘)的完整指南?我知道需要进行 InterOp 调用,但我正在寻找基于简单 WPF 表单的概念证明,或者可以使用的组件化版本。
相关资源:
最佳答案
请注意:这个问题收集了大量的反馈,下面的一些人提出了很好的观点或修正。因此,虽然我会将代码保留在这里(并可能对其进行更新),但我还创建了一个 WpfAppBar project on github 。随时发送请求请求。
同一个项目也构建为 WpfAppBar nuget package 我从问题中提供的第一个链接 (http://www.codeproject.com/KB/dotnet/AppBar.aspx) 中获取代码并修改它以执行两件事: 此方法不创建基类。 要使用,只需从普通 wpf 窗口中的任何位置调用此代码(比如单击按钮或初始化)。请注意,在窗口初始化之后才能调用它,如果尚未创建 HWND(如在构造函数中),则会发生错误。 使窗口成为应用栏: 将窗口恢复为普通窗口: 这是文件的完整代码 - 注意您需要将第 7 行的命名空间更改为适当的名称。
AppBarFunctions.SetAppBar( this, ABEdge.Right );
AppBarFunctions.SetAppBar( this, ABEdge.None );
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Threading;
namespace AppBarApplication
{
public enum ABEdge : int
{
Left = 0,
Top,
Right,
Bottom,
None
}
internal static class AppBarFunctions
{
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[StructLayout(LayoutKind.Sequential)]
private struct APPBARDATA
{
public int cbSize;
public IntPtr hWnd;
public int uCallbackMessage;
public int uEdge;
public RECT rc;
public IntPtr lParam;
}
private enum ABMsg : int
{
ABM_NEW = 0,
ABM_REMOVE,
ABM_QUERYPOS,
ABM_SETPOS,
ABM_GETSTATE,
ABM_GETTASKBARPOS,
ABM_ACTIVATE,
ABM_GETAUTOHIDEBAR,
ABM_SETAUTOHIDEBAR,
ABM_WINDOWPOSCHANGED,
ABM_SETSTATE
}
private enum ABNotify : int
{
ABN_STATECHANGE = 0,
ABN_POSCHANGED,
ABN_FULLSCREENAPP,
ABN_WINDOWARRANGE
}
[DllImport("SHELL32", CallingConvention = CallingConvention.StdCall)]
private static extern uint SHAppBarMessage(int dwMessage, ref APPBARDATA pData);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
private static extern int RegisterWindowMessage(string msg);
private class RegisterInfo
{
public int CallbackId { get; set; }
public bool IsRegistered { get; set; }
public Window Window { get; set; }
public ABEdge Edge { get; set; }
public WindowStyle OriginalStyle { get; set; }
public Point OriginalPosition { get; set; }
public Size OriginalSize { get; set; }
public ResizeMode OriginalResizeMode { get; set; }
public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam,
IntPtr lParam, ref bool handled)
{
if (msg == CallbackId)
{
if (wParam.ToInt32() == (int)ABNotify.ABN_POSCHANGED)
{
ABSetPos(Edge, Window);
handled = true;
}
}
return IntPtr.Zero;
}
}
private static Dictionary<Window, RegisterInfo> s_RegisteredWindowInfo
= new Dictionary<Window, RegisterInfo>();
private static RegisterInfo GetRegisterInfo(Window appbarWindow)
{
RegisterInfo reg;
if( s_RegisteredWindowInfo.ContainsKey(appbarWindow))
{
reg = s_RegisteredWindowInfo[appbarWindow];
}
else
{
reg = new RegisterInfo()
{
CallbackId = 0,
Window = appbarWindow,
IsRegistered = false,
Edge = ABEdge.Top,
OriginalStyle = appbarWindow.WindowStyle,
OriginalPosition =new Point( appbarWindow.Left, appbarWindow.Top),
OriginalSize =
new Size( appbarWindow.ActualWidth, appbarWindow.ActualHeight),
OriginalResizeMode = appbarWindow.ResizeMode,
};
s_RegisteredWindowInfo.Add(appbarWindow, reg);
}
return reg;
}
private static void RestoreWindow(Window appbarWindow)
{
RegisterInfo info = GetRegisterInfo(appbarWindow);
appbarWindow.WindowStyle = info.OriginalStyle;
appbarWindow.ResizeMode = info.OriginalResizeMode;
appbarWindow.Topmost = false;
Rect rect = new Rect(info.OriginalPosition.X, info.OriginalPosition.Y,
info.OriginalSize.Width, info.OriginalSize.Height);
appbarWindow.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,
new ResizeDelegate(DoResize), appbarWindow, rect);
}
public static void SetAppBar(Window appbarWindow, ABEdge edge)
{
RegisterInfo info = GetRegisterInfo(appbarWindow);
info.Edge = edge;
APPBARDATA abd = new APPBARDATA();
abd.cbSize = Marshal.SizeOf(abd);
abd.hWnd = new WindowInteropHelper(appbarWindow).Handle;
if( edge == ABEdge.None)
{
if( info.IsRegistered)
{
SHAppBarMessage((int)ABMsg.ABM_REMOVE, ref abd);
info.IsRegistered = false;
}
RestoreWindow(appbarWindow);
return;
}
if (!info.IsRegistered)
{
info.IsRegistered = true;
info.CallbackId = RegisterWindowMessage("AppBarMessage");
abd.uCallbackMessage = info.CallbackId;
uint ret = SHAppBarMessage((int)ABMsg.ABM_NEW, ref abd);
HwndSource source = HwndSource.FromHwnd(abd.hWnd);
source.AddHook(new HwndSourceHook(info.WndProc));
}
appbarWindow.WindowStyle = WindowStyle.None;
appbarWindow.ResizeMode = ResizeMode.NoResize;
appbarWindow.Topmost = true;
ABSetPos(info.Edge, appbarWindow);
}
private delegate void ResizeDelegate(Window appbarWindow, Rect rect);
private static void DoResize(Window appbarWindow, Rect rect)
{
appbarWindow.Width = rect.Width;
appbarWindow.Height = rect.Height;
appbarWindow.Top = rect.Top;
appbarWindow.Left = rect.Left;
}
private static void ABSetPos(ABEdge edge, Window appbarWindow)
{
APPBARDATA barData = new APPBARDATA();
barData.cbSize = Marshal.SizeOf(barData);
barData.hWnd = new WindowInteropHelper(appbarWindow).Handle;
barData.uEdge = (int)edge;
if (barData.uEdge == (int)ABEdge.Left || barData.uEdge == (int)ABEdge.Right)
{
barData.rc.top = 0;
barData.rc.bottom = (int)SystemParameters.PrimaryScreenHeight;
if (barData.uEdge == (int)ABEdge.Left)
{
barData.rc.left = 0;
barData.rc.right = (int)Math.Round(appbarWindow.ActualWidth);
}
else
{
barData.rc.right = (int)SystemParameters.PrimaryScreenWidth;
barData.rc.left = barData.rc.right - (int)Math.Round(appbarWindow.ActualWidth);
}
}
else
{
barData.rc.left = 0;
barData.rc.right = (int)SystemParameters.PrimaryScreenWidth;
if (barData.uEdge == (int)ABEdge.Top)
{
barData.rc.top = 0;
barData.rc.bottom = (int)Math.Round(appbarWindow.ActualHeight);
}
else
{
barData.rc.bottom = (int)SystemParameters.PrimaryScreenHeight;
barData.rc.top = barData.rc.bottom - (int)Math.Round(appbarWindow.ActualHeight);
}
}
SHAppBarMessage((int)ABMsg.ABM_QUERYPOS, ref barData);
SHAppBarMessage((int)ABMsg.ABM_SETPOS, ref barData);
Rect rect = new Rect((double)barData.rc.left, (double)barData.rc.top,
(double)(barData.rc.right - barData.rc.left), (double)(barData.rc.bottom - barData.rc.top));
//This is done async, because WPF will send a resize after a new appbar is added.
//if we size right away, WPFs resize comes last and overrides us.
appbarWindow.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,
new ResizeDelegate(DoResize), appbarWindow, rect);
}
}
}
关于c# - 你如何在 WPF 中进行 AppBar 对接(到屏幕边缘,如 WinAmp)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75785/
出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"
我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121
这可能是个愚蠢的问题。但是,我是一个新手......你怎么能在交互式rubyshell中有多行代码?好像你只能有一条长线。按回车键运行代码。无论如何我可以在不运行代码的情况下跳到下一行吗?再次抱歉,如果这是一个愚蠢的问题。谢谢。 最佳答案 这是一个例子:2.1.2:053>a=1=>12.1.2:054>b=2=>22.1.2:055>a+b=>32.1.2:056>ifa>b#Thecode‘if..."startsthedefinitionoftheconditionalstatement.2.1.2:057?>puts"f
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser